TLS Certificate Lifecycle
Also Known As
TL;DR
Explanation
A TLS certificate proves a server's identity and enables encrypted connections. The lifecycle: (1) Generate a private key and Certificate Signing Request (CSR) containing the domain and public key. (2) Submit the CSR to a Certificate Authority (CA). (3) CA validates domain control via DNS-01, HTTP-01, or TLS-ALPN-01 challenge. (4) CA signs and issues the certificate (DV, OV, or EV). (5) Install certificate and private key on the server; configure intermediate chain. (6) Monitor expiry with alerting at 30/14/7 days before expiry. (7) Renew before expiry (Let's Encrypt: 90-day certs, renew at 60 days). (8) On compromise: revoke via CRL or OCSP. Let's Encrypt and ACME protocol automate steps 1–5 and 7 via Certbot or acme.php. Certificate Transparency logs (CT logs) record every issued certificate publicly — useful for detecting mis-issuance and shadow certificates for your domain.
Diagram
flowchart TD
A[Generate private key + CSR] --> B[Submit to CA]
B --> C[Domain validation - DNS or HTTP challenge]
C --> D[CA issues certificate]
D --> E[Install cert + chain on server]
E --> F[Reload web server]
F --> G[Monitor expiry - alert at 30d]
G --> H{Expiry approaching?}
H -->|Yes - autorenew| B
H -->|Compromised| I[Revoke via CA + OCSP]
I --> A
style A fill:#1f6feb,color:#fff
style I fill:#f85149,color:#fff
style G fill:#238636,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Not installing the intermediate certificate chain — browsers show 'certificate not trusted' even though the leaf cert is valid.
- Renewing the certificate but forgetting to reload the web server (nginx/Apache) — the old expired cert keeps serving until the process restarts.
- No expiry monitoring or alerting — the certificate expires silently during a holiday weekend.
- Storing the private key in a world-readable location or committing it to git.
- Using a single certificate for many domains without Subject Alternative Names (SANs) — a wildcard `*.example.com` doesn't cover `example.com` itself.
Code Examples
# Manual renewal — easy to forget, no alerting:
# 1. Remember to check expiry once a year
# 2. Manually run certbot renew
# 3. Remember to reload nginx
# 4. Hope you didn't forget
# Also bad — private key world-readable:
$ chmod 644 /etc/ssl/private/example.com.key
# Automated renewal with Certbot + cron + reload:
# /etc/cron.d/certbot
0 */12 * * * root certbot renew --quiet --deploy-hook 'systemctl reload nginx'
# Or systemd timer (preferred):
# certbot.timer runs certbot.service twice daily automatically on modern systems
# Private key permissions — readable only by root/nginx user:
$ chmod 600 /etc/letsencrypt/live/example.com/privkey.pem
# Monitor expiry — alert at 30 days:
$ echo | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates
# Or use: https://github.com/drwetter/testssl.sh
# Check full chain is served:
$ openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep 'Certificate chain'