fjordtools / Guides / Check certificate expiry

Check when a certificate expires

How to read a certificate's end date from a file or a live server, script a check that exits nonzero before it expires, and why shorter lifetimes need it.

Fjordtools team · Published · 3 min read

Read the date

Every certificate has a Not after date. After it, clients refuse the certificate and you get certificate has expired. If you have the file, OpenSSL prints the date:

openssl x509 -noout -enddate -in cert.pem

The output is one line, notAfter=Jan 1 00:00:00 2036 GMT. To read it off a live server instead of a file, fetch the certificate the server really sends and pass it on:

openssl s_client -connect example.com:443 -servername example.com </dev/null | openssl x509 -noout -enddate

Check the server, not the file on disk. After a renewal many servers keep serving the old certificate until they are reloaded, so a new file proves nothing about what clients see.

You can also paste the certificate into the Certificate Decoder. It shows Not before and Not after, how long is left, and a warning when 30 days or fewer remain. Paste the whole chain and it counts the certificates that are expired, because an intermediate expiring breaks a site just as the leaf does.

Test it in a script

For a check you can run from cron or a pipeline, -checkend takes a number of seconds and exits nonzero if the certificate will expire within that time, zero if not[1]:

openssl x509 -noout -checkend 2592000 -in cert.pem

2592000 seconds is 30 days. It prints Certificate will not expire and exits 0, or Certificate will expire and exits 1, and it says the latter for a certificate that has already expired too. Put it in a loop over the hosts you care about:

for host in example.com example.org; do
  echo | openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null | openssl x509 -noout -checkend 2592000 >/dev/null || echo "$host expires within 30 days or could not be checked"
done

The loop prints nothing when every host is fine. A host that is down, or serves no certificate, also prints, because openssl x509 then has nothing to read and fails. That is what you want from a monitor: silence means all is well.

Why this matters more every year

Certificates are getting shorter. Let's Encrypt issues 90-day certificates today and says it will cut them to 45 days by 2028, as the CA/Browser Forum Baseline Requirements require of all publicly trusted CAs[2]. Its timeline, for new certificates:

  • 13 May 2026: the opt-in tlsserver profile issues 45-day certificates.
  • 10 February 2027: the default classic profile issues 64-day certificates.
  • 16 February 2028: the classic profile issues 45-day certificates[2].

A certificate you renew by hand once a year will not survive that. Expiry also stops being a reminder you can lean on: Let's Encrypt ended its expiration notification emails on 4 June 2025, saying more subscribers had reliable automation in place, and pointed people who still want notices to third-party monitoring[3]. If you rely on a CA email, you now have no safety net.

Automate renewal, and watch it separately

Two jobs, kept apart:

  1. Renew automatically. Use an ACME client and let it run on a schedule. Let's Encrypt recommends enabling ACME Renewal Information (ARI), which tells the client when to renew, and asks you to check that your automation copes with shorter lifetimes[2]. How you enable ARI differs per client, so read its documentation.
  2. Monitor what is actually served. Renewal can succeed while the server keeps the old certificate. The loop above reads the certificate from the live port, so it catches a renewal that was never loaded. Send its output somewhere a person looks.
Tip

Warn early enough to act, but not all the time. A 30-day warning leaves time on a 90-day certificate, yet on a 45-day certificate it fires for two thirds of the certificate's life. Pick a threshold of roughly a third of the lifetime and change 2592000 to match.

When it has already expired

Paste the certificate, or the whole chain, into the Decoder to see which one expired and how long ago. The page on certificate has expired lists the four usual causes, including a certificate that is fine on a client whose clock is wrong. If the message is the opposite, certificate is not yet valid, the clock is the first thing to check.

The Decoder runs in your browser. After the page has loaded it makes no network requests, and nothing you paste is sent anywhere. You can check that yourself.

Sources

  1. openssl-x509: the -checkend option, OpenSSL Project. Checked 8 November 2026.
  2. Decreasing Certificate Lifetimes to 45 Days, Let's Encrypt, 2 December 2025. Checked 8 November 2026.
  3. Ending Support for Expiration Notification Emails, Let's Encrypt, 22 January 2025. Checked 8 November 2026.

Tools mentioned

More guides are coming

See all guides.