AlertKite
← AlertKite

SSL certificate expired: what breaks, how to fix it now, and how to never repeat it

An expired certificate is the most avoidable outage there is. It fails for every visitor simultaneously, the browser warning implies your site is dangerous rather than misconfigured, and the date was known months in advance.

Auto-renewal is the obvious answer and it is not sufficient, because auto-renewal fails quietly too.

Check the expiry date from anywhere

# What the world sees — including any intermediate problems
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates -subject

# Is certbot's timer actually running?
systemctl list-timers | grep certbot
certbot renew --dry-run

Setting it up

  1. Renew now — certbot renew, or reissue through your host's panel.
  2. Reload the web server. A renewed certificate that is not loaded is still the old one.
  3. Verify from outside, not from the server: check what a browser actually receives.
  4. Add monitoring for the expiry date so the next one warns at 14, 7, 3 and 1 days.

Why auto-renewal is not enough

Certbot's timer can be disabled by an OS upgrade. The HTTP-01 challenge fails if a redirect was added in front of /.well-known. The renewal succeeds and nginx is never reloaded. All three are common, all three are silent, and all three end with an expired certificate on a site with auto-renewal configured.

Check from outside the server

The certificate on disk and the certificate being served are different facts. A load balancer, a CDN or a second vhost can serve something else entirely. The only check that means anything is the one that connects the way a browser does.

Do not forget the intermediate

A valid leaf certificate served without its intermediate chain fails on Android and on anything using the system trust store, while working perfectly in desktop Chrome. It is the failure that gets reported as “it works for me”.