Certificate monitoring: six assertions, the date is one

19/10/2026 · Laurent TLS and certificates
Certificate monitoring: six assertions, the date is one

Certificate monitoring means one thing to most tools: how many days until it expires. That is a real check and it is the one that fails least often, because on any site with automated renewal the expiry date is the part that already works.

What a certificate check should assert, all of it read from outside the server, is six things.

AssertionCatches
Days remainingRenewal that stopped happening
The chain as served is completeWorks in browsers, fails for APIs and older clients
The hostname is in the name listA subdomain added to DNS and not to the certificate
The issuer is the one you expectA certificate you did not request, or a fallback you did not notice
The certificate being served is the one on diskA renewal that ran and was never loaded
The protocol and cipher floorA configuration reverted by a panel or a migration

Read it from outside, per hostname, with SNI

Three qualifications in that sentence and each one is a distinct failure that a check performed differently would miss.

From outside, because the renewal job's exit code tells you the file was written and nothing about what the running server has in memory. A service that has not been reloaded since before the renewal serves the old certificate happily until the moment it expires. The file on disk is a separate object with separate questions, and inspecting one is not inspecting the other: what to verify in a certificate before it is installed anywhere.

Per hostname, because a host serves several sites and each has its own certificate. Checking the machine tells you about one of them.

With SNI, because a connection that does not name the host receives the default virtual host's certificate, which on shared infrastructure belongs to somebody else entirely. Any check built on a connection by IP address is validating a certificate no visitor will ever be shown: the same trap that makes openssl output look catastrophically wrong.

host=example.com
echo | openssl s_client -servername "$host" -connect "$host:443" 2>/dev/null \
  | openssl x509 -noout -enddate -issuer -ext subjectAltName

The threshold that fires too late

Most tools default to alerting a fixed number of days before expiry, commonly seven or fourteen. On a short-lived certificate that number is chosen from the wrong end of the problem.

Let's Encrypt issues certificates valid for ninety days, and the recommended practice is to renew when thirty days remain, with the client attempting renewal regularly rather than once (Let's Encrypt, Integration Guide, consulted 1 August 2026). Which means that by the time a certificate has twenty days left, renewal has been attempting and failing for over a week, unnoticed.

The useful alert is therefore not "expiry is near". It is "renewal should have happened by now and has not". For a ninety-day certificate renewed at thirty days, anything under about twenty-five days remaining is already an incident, and an alert at seven days is a report on a fire that has been burning for three weeks.

Set the threshold from the renewal point of the certificate you actually have, not from a round number. For a one-year commercial certificate the arithmetic is different and the number is larger, because the recovery involves a human, a purchase and possibly a validation step: the margin has to fit the slowest step in your own process.

The issuer check, which almost nobody runs

One string comparison, and it catches two entirely different problems.

The dull one is a fallback you did not notice. A host's control panel reissues a certificate from its own authority when it thinks yours is missing, or a CDN provisions one automatically. The site works, the padlock is fine, and the certificate you thought you were managing has quietly been replaced by one you cannot renew or revoke. On an internal service the replacement is frequently one the machine signed for itself, which is the right answer in three specific situations and a warning sign everywhere else: when signing your own is correct.

The alarming one is a certificate issued for your client's domain that nobody at your end requested. Anyone who can pass a domain validation check can obtain a certificate for a name. That includes somebody who has temporarily controlled the DNS, or an email address at the domain, or a subdirectory of the web root.

Public certificate transparency logs make this observable. Every publicly trusted certificate is logged, and the logs are searchable:

curl -s 'https://crt.sh/?q=example.com&output=json' \
  | jq -r '.[] | "\(.not_before) \(.issuer_name) \(.name_value)"' | sort -u | tail -20

Run that per client domain on a schedule, keep the previous result, and alert on new rows. It is a handful of lines and it is the cheapest detection you will ever add for a category of problem that has no other symptom, because a fraudulently issued certificate does not break anything on your side. That is the whole point of it.

What to check besides the leaf

The intermediate's own dates. Intermediates expire too, on their own schedule, and a chain containing an expired intermediate fails in exactly the same way as an expired leaf while your leaf-only monitoring reports plenty of time remaining.

echo | openssl s_client -servername "$host" -connect "$host:443" -showcerts 2>/dev/null \
  | awk '/BEGIN CERT/,/END CERT/' \
  | openssl storeutl -noout -text /dev/stdin 2>/dev/null | grep -E 'Not After|Issuer:'

Whether the chain is complete as served. Browsers repair an incomplete chain by fetching the missing certificate themselves, which is why this fault is invisible in the tool you would naturally test with and visible to every payment webhook and mobile client. The distinction between a chain that works and a chain that is complete is in the second of the three commands.

The protocol floor. A migration, a panel update or a reverted configuration file can quietly re-enable an obsolete protocol version. Nothing breaks, nobody notices, and the client fails their next security questionnaire.

Where the monitoring has to live, and the list it works from

Not on the machine being checked. A certificate check that runs on the same server as the site shares every failure mode with it, and a suspended account takes the watcher out with the watched.

And the list of hostnames matters more than the checks. The certificate that lapses is never the main site; it is the retired domain still redirecting, the mail hostname, the internal API, the load balancer terminating TLS separately from the origin. Build the list from DNS and from your inventory rather than from the sites you think about, then assert all six of the above on every entry.

Everything above is worth the effort for one reason: this is the failure that arrives on a known date and takes the entire site with it when it does, including the parts of it that have no human to click through a warning: the only outage published in advance.

Back to contents

Share this post.
Stay up-to-date

Subscribe to our newsletter

Don't miss this

You might also like