SSL Certificate Automation with Let's Encrypt
Automate SSL/TLS certificate issuance and renewal using Let's Encrypt, Certbot, and ACME. Cover HTTP and DNS challenges, wildcard certificates, and monitoring.
Let's Encrypt and ACME
Let's Encrypt is a free, automated Certificate Authority (CA) that issues SSL/TLS certificates. It uses the ACME protocol (Automatic Certificate Management Environment) to verify domain ownership and issue certificates without human intervention.
Key facts: - Certificates are valid for 90 days (short-lived by design for security). - Automated renewal eliminates the risk of expired certificates. - Supports single-domain, multi-domain (SAN), and wildcard certificates. - Rate limit: 50 certificates per registered domain per week.
Certbot: The Standard Client
Certbot is the recommended ACME client:
# Install on Ubuntu
sudo apt install certbot python3-certbot-nginx
# Obtain certificate with Nginx plugin (automatic configuration)
sudo certbot --nginx -d example.com -d www.example.com
# Obtain certificate only (manual Nginx config)
sudo certbot certonly --nginx -d example.com
Certbot automatically:
1. Proves domain ownership via HTTP-01 challenge.
2. Downloads the certificate and private key.
3. Configures Nginx SSL directives (with --nginx plugin).
4. Sets up a systemd timer for automatic renewal.
Challenge Types
HTTP-01 Challenge
The most common method. Let's Encrypt sends an HTTP request to http://example.com/.well-known/acme-challenge/<token>:
# Certbot handles this automatically, or use standalone mode:
sudo certbot certonly --standalone -d example.com
# (Requires port 80 to be free)
# Or webroot mode (no port conflict):
sudo certbot certonly --webroot -w /var/www/html -d example.com
DNS-01 Challenge
Required for wildcard certificates. You must create a TXT record in your domain's DNS:
# Wildcard certificate via DNS challenge
sudo certbot certonly --manual --preferred-challenges dns \
-d "*.example.com" -d example.com
# Certbot will ask you to create:
# _acme-challenge.example.com TXT "random-verification-string"
For automation, use DNS plugins that update records via API:
# Cloudflare DNS plugin
sudo apt install python3-certbot-dns-cloudflare
# /etc/letsencrypt/cloudflare.ini
dns_cloudflare_api_token = your-api-token
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "*.example.com" -d example.com
Automatic Renewal
Certbot installs a systemd timer that checks for renewal twice daily:
# Check timer status
sudo systemctl status certbot.timer
# Test renewal (dry run, no actual changes)
sudo certbot renew --dry-run
# Manual renewal
sudo certbot renew
Renewal Hooks
Run commands after successful renewal (e.g., reload Nginx):
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
Make the hook executable: chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Certificate File Locations
/etc/letsencrypt/live/example.com/
├── fullchain.pem # Certificate + intermediate CA (use this in Nginx)
├── privkey.pem # Private key
├── cert.pem # Server certificate only
└── chain.pem # Intermediate CA certificate
Monitoring Certificate Expiry
Even with automation, monitor certificates as a safety net:
# Check expiry date
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# One-liner for days remaining
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2 | xargs -I{} date -d {} +%s | \
xargs -I{} echo $(( ({} - $(date +%s)) / 86400 )) days remaining
Set up alerts if a certificate has fewer than 14 days remaining — this gives you time to investigate renewal failures.