Back to blog
ssl monitoring best-practices

How to monitor SSL certificate expiry before it takes your site down

An expired TLS certificate is a full outage that you can see coming weeks ahead. Here is how SSL certificates expire, why auto-renewal is not enough, how to check expiry yourself, and how to monitor it so a renewal never slips.

The Cronaut team

An expired SSL certificate is one of the few outages you can see coming weeks in advance, and one of the most common ones to still get caught by. The certificate is valid right up to a known date and time. Then it lapses, and every browser replaces your site with a full page security warning. The visitor sees a red screen that says the connection is not private, and to most people that looks exactly like a site that has been hacked. They back away and do not come back.

The frustrating part is that nothing about this is a surprise. The expiry date was printed on the certificate the day it was issued. The only thing standing between you and a calm renewal is something that watches the clock and tells you before the date arrives. This guide covers how certificates expire, why the automation you already have is not enough on its own, how to check expiry yourself, and how to monitor it so the renewal never slips.

What actually happens when a certificate expires

A TLS certificate is how a browser confirms it is really talking to your domain over an encrypted connection. Every certificate has a fixed validity window with a start date and an end date. Once the clock passes that end date, the certificate is no longer valid, and there is no grace period built into the browser. Validity does not fade out. It is fine one second and rejected the next.

When it lapses, browsers stop trusting the connection entirely. Chrome, Safari, Firefox and the rest all throw an interstitial warning that the user has to actively click through, and many of them make that deliberately hard to do. Your real pages never load. Search engine crawlers treat the site as unreachable. Any API that other apps call over HTTPS starts failing every request, because automated clients reject an invalid certificate by default and have no human to click past the warning.

So an expired certificate is not a cosmetic problem or a slow degradation. It is a complete outage that hits every visitor and every machine client at the same instant, triggered by a date you knew about months ago.

Why certificates lapse even with auto-renewal

Most people set up automatic renewal once, usually with Let’s Encrypt and a tool like certbot, and assume the problem is solved forever. Auto-renewal is a real improvement, but it fails more often than people expect, and it tends to fail quietly. Here are the ways it breaks in practice.

  • The renewal hook breaks after a server change. You upgrade the OS, move the site to a new box, or change a path, and the cron job or systemd timer that runs the renewal no longer fires. Nothing errors loudly. The job just stops running.
  • The domain validation stops resolving. Let’s Encrypt has to prove you still control the domain on every renewal. If you use a DNS challenge and an API token expires, or an HTTP challenge and a redirect rule starts intercepting the validation path, the renewal is refused.
  • A new certificate is issued but never loaded. This one is sneaky. The renewal succeeds and a fresh certificate sits on disk, but the web server was never reloaded, so it keeps serving the old one until that old one expires.
  • A wildcard or multi-domain certificate drifts. You add a new subdomain that the existing certificate does not cover, and that hostname starts serving a mismatched certificate even though the main domain is fine.
  • A managed certificate is not as managed as you think. A load balancer, CDN, or hosting panel that handles certificates for you can still get stuck on a manual upload, a paid certificate from a CA that does not auto-renew, or a configuration that quietly fell out of sync.

The common thread is that the automation reports success or stays silent in every one of these cases, and the certificate still lapses. Auto-renewal removes most of the manual work. It does not remove the need for an independent check that confirms the work actually happened. That independent check is what monitoring is.

How to check certificate expiry yourself

Before you automate this, it helps to see exactly what you are measuring. You can read the expiry date straight from the certificate your domain is serving with one command.

echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -dates

That prints the notBefore and notAfter dates. The notAfter line is your deadline. If you just want the days remaining, this version does the math for you using the certificate’s end date.

expiry=$(echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)
echo "Expires: $expiry"

This is genuinely useful for a one-off check, and you can wrap it in a script. The problem is that a script only tells you the truth at the moment you run it. To catch a renewal that breaks three months from now, you need that check to run on a schedule, forever, and to reach you when the number gets low. That is the part a manual command cannot do, and it is exactly where most homegrown setups quietly rot. The script gets written, runs for a while, then the box it lives on gets rebuilt and nobody notices it stopped.

How to monitor it properly

Good SSL monitoring is a small set of habits. None of it is complicated, and together it turns a silent deadline into a calm, scheduled renewal.

Watch the served certificate, from the outside

Check the certificate your domain actually serves over the public internet, the same one a real browser receives. Do not check a certificate file sitting on disk, because that file can be fresh while the web server is still serving an old one it never reloaded. The thing that matters is what visitors get, so measure that. This is the same principle as checking website uptime from outside your own infrastructure rather than from a box that goes down with the site.

Warn weeks ahead, not on the day

The whole value of monitoring a certificate is lead time. Knowing it expired is useless, because by then you are already down. Knowing it expires in two weeks is the entire point. Set the warning far enough out that you have room to investigate why auto-renewal did not fire, fix it, and confirm the new certificate is being served, all without any urgency. A degraded warning with comfortable lead time is the difference between a calm afternoon task and a 2am scramble.

Treat an expiring certificate as a degraded state, not a hard failure

A certificate that expires in ten days is not down, but it is not healthy either. The right signal is a degraded state that escalates as the date gets closer. That way the warning shows up clearly without paging you like a real outage, and it stays visible until you have renewed. This fits the same up, degraded, down model that good monitoring uses for everything else, so an expiring certificate sits on the same dashboard as a slow endpoint or a late cron job.

Validate the certificate on every uptime check too

Expiry is the most common certificate failure, but it is not the only one. A certificate can become invalid because the served hostname no longer matches, the chain is incomplete, or it was revoked. If your uptime monitoring validates the certificate on every run, you catch those cases the moment they happen, on top of the scheduled expiry warning. One check covers both the slow countdown and the sudden break.

Cover every hostname, including the ones you forget

The certificate on your main domain is the one everybody remembers. The ones that bite you are the API subdomain, the staging host that customers somehow found, the marketing site on a separate certificate, and the wildcard that does not actually cover the subdomain you added last month. List every hostname that serves HTTPS and put a check on each. An expired certificate on api.example.com breaks every integration just as hard as one on the front page.

Route the warning where you already look

A warning nobody sees is not monitoring. Send the expiry alert to the place you actually watch, whether that is email, Slack, Discord, or a webhook into your on-call tool, and make the message say which hostname and how many days are left. The renewal is a small task, but only if it lands in front of you while there is still time to do it calmly.

Put it on your status page

If a certificate does lapse before you catch it, the next thing that happens is people asking whether the site is broken for everyone. A public status page that updates itself answers that before the support tickets start. The cleanest setup is one where the degraded certificate opens the incident on its own, so you are not posting manual updates during the one moment you are busy renewing. More on that in status pages without the busywork.

Putting it together

Monitoring SSL certificate expiry comes down to a handful of habits. Check the certificate your domain actually serves, from the outside. Warn yourself weeks ahead so a renewal is never urgent. Treat an expiring certificate as a degraded state that stays visible until you fix it. Validate the certificate on your uptime checks so you catch the sudden breaks too. Cover every hostname, not just the obvious one. None of it requires a heavy platform, and all of it prevents an outage that is completely avoidable.

Cronaut is built to make this the default. You give it a domain, and it inspects the certificate your site actually serves, tracks the days remaining, and moves the check to a degraded state with comfortable lead time before expiry, alerting you by email, Slack, Discord or webhook. The same certificate is validated on every uptime check, so an expiry countdown and a sudden invalid certificate both show up in one place. A degraded certificate can open an incident on your public status page automatically, and the same engine watches your cron jobs and HTTP endpoints, so everything that can break shows up on one dashboard. See SSL certificate monitoring for how the checks work, or read how to monitor website uptime for the HTTP side of the same engine.

Try Cronaut free

Uptime, cron and a self-updating status page in one tool.

Start free