Introduction

When an SSL/TLS certificate expires, modern browsers display a full-page security warning that blocks users from accessing the site. Users see Your connection is not private (Chrome), Warning: Potential Security Risk Ahead (Firefox), or This connection is not private (Safari). Most non-technical users will not proceed past this warning, effectively making the site unavailable. Certificate expiration is one of the most common and easily preventable causes of website downtime.

Symptoms

  • Browser shows full-page SSL warning before loading the site
  • curl -vI https://example.com shows SSL certificate problem: certificate has expired
  • openssl x509 -in cert.pem -noout -dates shows notAfter date in the past
  • API clients and mobile apps fail with SSL verification errors
  • Site works with HTTP but not HTTPS

Common Causes

  • Certificate renewal process failed silently (ACME challenge error, DNS validation failure)
  • Automated renewal (certbot cron) not configured or not running
  • Certificate purchased for 1 year but renewal forgotten
  • New certificate generated but not deployed to the web server
  • Certificate authority changed and old cert expired before new one installed

Step-by-Step Fix

  1. 1.Verify the certificate is expired:
  2. 2.```bash
  3. 3.openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
  4. 4.openssl x509 -noout -dates -subject
  5. 5.# notAfter=Apr 01 00:00:00 2026 GMT (if this is in the past, it is expired)
  6. 6.`
  7. 7.Renew the certificate:
  8. 8.```bash
  9. 9.# For Let's Encrypt / Certbot:
  10. 10.sudo certbot renew --force-renewal
  11. 11.# If DNS challenge is needed:
  12. 12.sudo certbot certonly --manual --preferred-challenges dns -d example.com -d www.example.com
  13. 13.`
  14. 14.For manually purchased certificates, obtain a new one from the CA:
  15. 15.Log in to your certificate provider (DigiCert, Sectigo, etc.), request a reissue, and download the new certificate files.
  16. 16.Install the new certificate on the web server:
  17. 17.```bash
  18. 18.# Nginx
  19. 19.sudo cp new-cert.pem /etc/nginx/ssl/example.com.crt
  20. 20.sudo cp new-key.pem /etc/nginx/ssl/example.com.key
  21. 21.sudo systemctl reload nginx

# Apache sudo cp new-cert.pem /etc/apache2/ssl/example.com.crt sudo cp new-key.pem /etc/apache2/ssl/example.com.key sudo systemctl reload apache2 ```

  1. 1.Verify the new certificate is active:
  2. 2.```bash
  3. 3.openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | \
  4. 4.openssl x509 -noout -dates
  5. 5.# Should show the new notAfter date in the future
  6. 6.`
  7. 7.Set up automated renewal monitoring:
  8. 8.```bash
  9. 9.# Check expiration with a script
  10. 10.EXPIRY=$(openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -enddate | cut -d= -f2)
  11. 11.EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
  12. 12.NOW_EPOCH=$(date +%s)
  13. 13.DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
  14. 14.echo "Certificate expires in $DAYS_LEFT days"
  15. 15.`

Prevention

  • Use Let's Encrypt with automated renewal (certbot renew cron) for zero-maintenance certificates
  • Set up certificate expiration monitoring with alerts at 30, 14, and 7 days
  • Use ACME DNS challenge for wildcard certificates that auto-renew
  • Implement certificate transparency monitoring to detect unexpected changes
  • Document the certificate renewal procedure for manually-purchased certificates