info@pccvdi.com Pashim Vihar, New Delhi

SSL/TLS Certificate Management: Automation, Monitoring, and Best Practices

SSL/TLS certificates are the foundation of web security, encrypting data in transit and establishing trust between clients and servers. Yet certificate management remains one of the most neglected areas of IT operations — until a certificate expires and brings down production services. This guide covers automation, monitoring, and best practices for managing certificates at scale.

Understanding Certificate Types

Type Validation Use Case Cost
Domain Validated (DV) Domain ownership only Blogs, small sites, APIs Free (Let’s Encrypt) to $50/year
Organization Validated (OV) Domain + organization identity Business websites, intranets $50-200/year
Extended Validation (EV) Thorough business verification Banks, e-commerce, government $200-1000/year
Wildcard All subdomains (*.example.com) Multi-subdomain environments $50-500/year
SAN/Multi-Domain Multiple specific domains Hosting multiple sites on one IP $100-600/year

Let’s Encrypt Automation with Certbot

Let’s Encrypt provides free DV certificates with 90-day validity. Certbot automates issuance and renewal.

Initial Setup (Nginx)

# Install Certbot
sudo apt update
sudo apt install certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com

# Certbot automatically:
# 1. Verifies domain ownership via HTTP-01 challenge
# 2. Obtains the certificate from Let's Encrypt
# 3. Configures Nginx SSL directives
# 4. Sets up auto-renewal via systemd timer

Wildcard Certificates (DNS-01 Challenge)

# Wildcard requires DNS-01 validation
sudo certbot certonly --manual --preferred-challenges dns \
  -d "*.example.com" -d "example.com"

# For automated DNS validation with Cloudflare:
sudo apt install python3-certbot-dns-cloudflare

# Create Cloudflare credentials file
cat > /etc/letsencrypt/cloudflare.ini << EOF
dns_cloudflare_api_token = your-api-token-here
EOF
chmod 600 /etc/letsencrypt/cloudflare.ini

# Automate wildcard renewal
sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d "*.example.com" -d "example.com"

Nginx SSL Configuration Best Practices

# /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# Session caching
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# HSTS (strict transport security)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Additional security headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;

Full Nginx Server Block

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/nginx/snippets/ssl-params.conf;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Certificate Monitoring

Automated monitoring prevents surprise expirations:

Shell Script for Expiry Checking

#!/bin/bash
# check-ssl-expiry.sh - Check SSL certificate expiration
DOMAINS="example.com api.example.com shop.example.com"
ALERT_DAYS=14

for domain in $DOMAINS; do
  expiry=$(echo | openssl s_client -servername "$domain" \
    -connect "$domain:443" 2>/dev/null | \
    openssl x509 -noout -enddate | cut -d= -f2)

  expiry_epoch=$(date -d "$expiry" +%s)
  now_epoch=$(date +%s)
  days_left=$(( (expiry_epoch - now_epoch) / 86400 ))

  if [ "$days_left" -lt "$ALERT_DAYS" ]; then
    echo "WARNING: $domain expires in $days_left days ($expiry)"
    # Send alert via email, Slack, PagerDuty, etc.
  else
    echo "OK: $domain - $days_left days remaining"
  fi
done

Prometheus + Blackbox Exporter

# prometheus.yml
scrape_configs:
  - job_name: 'ssl-expiry'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - https://example.com
        - https://api.example.com
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - target_label: __address__
        replacement: blackbox-exporter:9115

# Alert rule
groups:
  - name: ssl
    rules:
      - alert: SSLCertExpiringSoon
        expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 14
        labels:
          severity: warning
        annotations:
          summary: "SSL cert for {{ $labels.instance }} expires in less than 14 days"

Renewal Strategies

  • Let's Encrypt: Auto-renewal via certbot renew cron job or systemd timer. Runs twice daily, only renews when within 30 days of expiry.
  • Commercial certificates: Set calendar reminders 30 days before expiry. Use monitoring tools to send automated alerts.
  • Internal/private CAs: Use tools like step-ca or cfssl for short-lived certificates with automatic rotation.

Certbot Auto-Renewal Verification

# Check renewal timer is active
sudo systemctl status certbot.timer

# Dry run to test renewal
sudo certbot renew --dry-run

# Post-renewal hook to reload Nginx
# /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
systemctl reload nginx

Professional SSL Management

At PCCVDI Solutions, we manage SSL/TLS certificates for organizations running hundreds of domains across multiple servers and cloud platforms. From initial certificate procurement to automated monitoring and renewal pipelines, we ensure your certificates never expire unexpectedly. Contact our security team for a free SSL audit of your infrastructure.