SSL Certificate Expiring
An expiring certificate is one of the few outages you can fix completely before anyone notices. You have days, not minutes. Work through this in order and do not skip step 4 — a renewed certificate that was never loaded is the most common way this alert comes back an hour later.
Symptom
Section titled “Symptom”DownBad reports that the certificate expires in N days, or that it has already
expired. Once it does expire, every browser shows a full-page interstitial
(NET::ERR_CERT_DATE_INVALID in Chrome), API clients fail their TLS handshake,
and anything doing certificate pinning stops dead.
SSL monitors carry two thresholds. The default warning threshold is 30 days and the default critical threshold is 7 days; the check fails inside the critical window, so the alert fires while there is still time to renew rather than at the moment the certificate dies.
Likely causes
Section titled “Likely causes”- Auto-renewal broke silently, weeks ago. A disabled systemd timer, a renewal hook that exits non-zero, or an ACME HTTP-01 challenge that a new redirect rule or WAF now intercepts. The renewal has been failing since long before you were alerted.
- The certificate was renewed but never deployed. The new file is on disk; the running server still holds the old one in memory. Renewal does not reload your server.
- Renewed on one node out of several. The load balancer still serves the stale certificate from the node you forgot.
- You are not looking at the certificate you think you are. DownBad sends SNI, so it sees what a browser sees. If your host serves a different certificate without SNI, your own testing may be checking the wrong one.
- A DNS-01 renewal is failing on an expired API token at your DNS provider. Wildcard certificates fail this way and nothing else on the box notices.
- The site moved hosts and the new host issued its own certificate for a hostname you are not monitoring.
Fix steps
Section titled “Fix steps”-
See what is actually being served, not what is on disk:
Terminal window echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \| openssl x509 -noout -dates -issuer -subjectnotAfteris the date that matters. Do this for every hostname you serve — apex andwwware frequently different certificates. -
Renew, using whichever of these matches your stack:
Terminal window sudo certbot renewsudo systemctl reload nginxIf renewal fails, run
sudo certbot renew --dry-runand read the error. An HTTP-01 failure almost always means a redirect or a WAF rule is intercepting/.well-known/acme-challenge/.Caddy renews automatically and reloads itself. If it has not, the reason is in the log:
Terminal window sudo journalctl -u caddy --since "7 days ago" | grep -i "certificate\|acme"The usual causes are port 80 being unreachable from outside or a rate limit at the CA after repeated failed attempts.
Check SSL/TLS → Edge Certificates in the dashboard. Universal SSL renews on its own; a stuck renewal is normally a CAA record that does not authorise the issuing CA, or a domain whose validation records were removed. If you are on Full (strict), the certificate on your origin needs renewing too — that is the one this alert is about.
Renew through your CA’s console, then install all of it: the leaf certificate and the intermediate chain, in the order your server expects. A missing intermediate validates fine on your machine, which has it cached, and fails for everyone else.
-
Reload the server. Renewal writes a file; it does not restart anything.
systemctl reload nginx,apachectl graceful, or whatever your stack calls it — and on every node, not just the one you are logged into. -
Verify with the same openssl command from step 1. The
notAfterdate must have moved. If it has not, you renewed a certificate the server is not using. -
Re-run the check from the monitor rather than waiting. SSL monitors default to an hourly interval, so the incident will otherwise stay open for up to an hour after you have fixed it.
Prevention
Section titled “Prevention”- Automate renewal and then verify the automation.
certbot renew --dry-runon a schedule catches a broken renewal months before the certificate matters. - Put the reload in the renewal hook (
--deploy-hook), not in your memory. - Keep the warning threshold at 21 days or more. Let’s Encrypt certificates live 90 days and renew at 30; a 7-day warning gives you exactly one weekend to notice.
- Monitor every hostname your customers actually type, including
www, apex, and any vanity or alias domain. They are separate certificates and they fail separately. - Alert somewhere a human reads. Certificate expiry is the one outage with a scheduled start time; missing it is a notification problem, not a TLS problem. If the alert never reached you, see Not Receiving Notifications.