Certificate expiration is the outage you always see coming and somehow never prevent. Here’s how to automate SSL so it stops being a problem.
The Problem#
SSL certificates expire. When they do:
- Users see scary browser warnings
- APIs reject connections
- Mobile apps fail silently
- Trust is broken
And it’s always on a Friday night.
Let’s Encrypt + Certbot#
Free, automated, trusted certificates.
Basic Setup#
1
2
3
4
5
6
7
8
| # Install certbot
apt install certbot python3-certbot-nginx
# Get certificate (nginx plugin handles everything)
certbot --nginx -d example.com -d www.example.com
# Test renewal
certbot renew --dry-run
|
Certbot adds a cron job automatically for renewal.
DNS Challenge for Wildcards#
1
2
| certbot certonly --manual --preferred-challenges dns \
-d "*.example.com" -d example.com
|
You’ll need to add a TXT record to prove domain ownership.
Kubernetes Cert-Manager#
Install#
1
| kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.0/cert-manager.yaml
|
ClusterIssuer#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
|
Ingress Annotation#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app
port:
number: 80
|
Cert-manager watches for this annotation and handles everything.
AWS Certificate Manager#
For AWS services (ALB, CloudFront, API Gateway):
1
2
3
4
| aws acm request-certificate \
--domain-name example.com \
--subject-alternative-names "*.example.com" \
--validation-method DNS
|
ACM certificates auto-renew. Use them wherever AWS supports them.
Monitoring Certificates#
Check Expiration#
1
2
| echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
|
Prometheus Alert#
1
2
3
4
5
6
7
| - alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 14
for: 1h
labels:
severity: warning
annotations:
summary: "SSL cert expires in {{ $value | humanizeDuration }}"
|
Common Mistakes#
1. Not Including All Domains#
1
2
3
4
5
| # Bad: Missing www
certbot --nginx -d example.com
# Good: Include all variants
certbot --nginx -d example.com -d www.example.com
|
2. Forgetting to Reload#
1
2
| # Reload after renewal
certbot renew --post-hook "systemctl reload nginx"
|
3. Wrong Certificate Chain#
1
2
3
| # Good: Full chain
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
|
The SSL Automation Checklist#
SSL should be invisible. If you’re thinking about certificates, something’s wrong.
The best SSL automation is the one you forget exists — until you realize you haven’t had a certificate emergency in years.