LucidStack
Features
Solutions
Resources
Pricing
Guide #ssl #domains #expiry

How to monitor SSL certificate and domain name expiry

SSL/TLS certificates and domain names: why they still expire, how to check them with openssl and RDAP, and which alert schedule to use.

The LucidStack team lucidstack.dev
Published
Reading time
7 min read
On this page
  1. Why expiries still happen
  2. Checking a certificate by hand with openssl
  3. Reading the expiry date
  4. Testing the deadline in a script
  5. Comparing the file with the served certificate
  6. Checking the chain and other services
  7. Let's Encrypt: 90-day certificates
  8. Checking a domain with RDAP rather than WHOIS
  9. Statuses to watch
  10. Name-server changes
  11. Which alert schedule to use
  12. Keeping an inventory across clients
  13. What LucidStack does automatically
  14. In short

An expired SSL/TLS certificate shows every visitor a full-screen warning, breaks API calls and can stop email from being delivered. An expired domain name is worse: the website, the email and everything else that depends on the domain vanish at once. Yet both outages are entirely predictable, since the expiry date is known months in advance.

This guide explains why these expiries still happen despite automatic renewal, how to check a certificate and a domain by hand, which alert schedule to adopt, and how to keep an inventory when you look after dozens of clients.

Why expiries still happen

Automatic renewal has also created a false sense of security. The most common causes:

  • Automatic renewal fails silently. A scheduled task lost during a server migration, an HTTP challenge blocked by a new firewall rule or redirect, a changed DNS record: the ACME client fails and nobody reads its logs.
  • The certificate is renewed but not deployed. The new file is on disk, but the web server was never reloaded and keeps serving the old certificate from memory. The same thing happens when the certificate has to be copied by hand to a load balancer, a CDN or a second server.
  • The intermediate chain is incomplete. The certificate itself is valid, but the server does not send the intermediate certificate. Some browsers work around it, so the site looks fine, while API clients, mobile apps and command-line tools fail.
  • The domain belongs to a former employee. The registrar account was opened with a personal email address and the renewal is charged to their card: the card expires, the reminders land in an inbox nobody reads, and the domain lapses.

On top of that, Let's Encrypt stopped sending expiry reminder emails in 2025: that safety net is gone.

Checking a certificate by hand with openssl

Reading the expiry date

This command connects to the server, fetches the certificate it presents and prints the issuer and the end of validity:

bash
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -issuer -enddate
text
issuer=C = US, O = Let's Encrypt, CN = R11
notAfter=Dec 14 08:12:45 2026 GMT

The -servername option is essential whenever several sites share an IP address: without it, you may end up reading another site's certificate.

Testing the deadline in a script

The -checkend option takes a number of seconds and returns a non-zero exit code if the certificate expires within that time. Here, 14 days:

bash
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -checkend 1209600 || echo "Certificate expires in less than 14 days"

Comparing the file with the served certificate

To catch a certificate that was renewed but never loaded, compare the date of the file on disk with the one returned by the command above:

bash
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -enddate

If the file is newer than what the server presents, a reload is missing. With certbot, a deploy hook fixes this for good:

bash
certbot renew --deploy-hook "systemctl reload nginx"

Checking the chain and other services

Run openssl s_client without the second openssl x509 and look at the Verify return code line near the end of the output. 0 (ok) means the chain is valid; 21 (unable to verify the first certificate) almost always points to a missing intermediate. Mail servers have certificates too, which you can test with STARTTLS:

bash
openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com

Let's Encrypt: 90-day certificates

Let's Encrypt certificates are valid for 90 days. The recommended practice is to renew them when about 30 days remain, which is what certbot does by default. The direct consequence: a Let's Encrypt certificate with 20 days left is not a certificate due for renewal soon, it is a renewal that has already failed.

Lifetimes are getting even shorter. CA/Browser Forum rules have capped public certificates at 200 days since March 2026, and will bring that down to 100 days in 2027 and 47 days in 2029; Let's Encrypt has announced a gradual move to 45 days. More renewals mean more chances to fail. The Let's Encrypt documentation covers good practice.

Checking a domain with RDAP rather than WHOIS

WHOIS returns free text whose format varies from one registry to the next. RDAP, its official successor, answers in structured, standardised JSON over HTTPS. For generic top-level domains such as .com, ICANN made it the authoritative source in early 2025.

The rdap.org service redirects to the right registry's RDAP server, hence the -L option:

bash
curl -sL https://rdap.org/domain/example.com \
  | jq '{status, nameservers: [.nameservers[].ldhName], expiration: (.events[] | select(.eventAction == "expiration") | .eventDate)}'

You can also query the registry directly, for example Verisign for .com or Afnic for .fr. IANA publishes the official list of servers per TLD in its RDAP bootstrap file.

bash
curl -s https://rdap.verisign.com/com/v1/domain/example.com
curl -s https://rdap.nic.fr/domain/example.fr

Statuses to watch

The status field deserves as much attention as the date. The clientHold status (set by the registrar) and serverHold (set by the registry) remove the domain from the DNS zone: it is still registered to you, but it no longer resolves. Typical causes are an unpaid invoice, an unverified registrant email address or an abuse procedure. In RDAP these statuses appear as client hold and server hold. Others, such as redemption period or pending delete, mean the domain has already expired.

Name-server changes

A name-server change you did not ask for is a classic sign of domain hijacking, for example after a registrar account has been compromised. Regularly compare the RDAP list with reality using dig NS example.com +short, and treat any unexpected difference as a security incident. DNS monitoring complements this check by detecting changes to the records themselves.

Which alert schedule to use

A single reminder is not enough: it arrives during the holidays, gets lost in a shared inbox or lands when nobody has time. Stagger them.

Reminder SSL/TLS certificate Domain name
First 30 days 60 days
Second 14 days 30 days
Urgent 7 days 7 days
Last 1 day 1 day

Domains need a longer lead time: you may have to get the client's approval, recover access to the registrar account, update a payment method or start a transfer, which takes several days. A certificate, on the other hand, can be renewed in minutes once you have found the cause.

Send these reminders to a team channel rather than an individual, and do not page your on-call engineer for a 30-day reminder: it is a warning, not an outage.

Keeping an inventory across clients

For an agency or a freelancer, the real problem is not checking a domain, it is knowing which ones exist and who is responsible for them. A simple inventory, kept up to date, records for each domain:

  • the registrar and the account that holds it (a generic agency or client address, never a personal one);
  • who pays, with which payment method and when that method expires;
  • whether auto-renewal is switched on;
  • the DNS host, where the certificates live (server, CDN, load balancer) and how they are renewed;
  • the client contact to notify.

Keep the credentials in a shared password manager, and review the inventory whenever someone joins or leaves the team. Our uptime monitoring checklist for web agencies covers the rest of the ground.

What LucidStack does automatically

LucidStack builds on what you already monitor. Every HTTPS monitor checks the certificate on each run, as do mail servers using STARTTLS or TLS and encrypted WebSockets. You get reminders 30, 14, 7 and 1 day before expiry, and an immediate alert if the certificate becomes invalid: incomplete chain, hostname mismatch, expired certificate. A change of issuer is flagged as well. The details are on the SSL certificate monitoring page.

On the domain side, the domains used by your monitors are detected automatically and checked every day via RDAP, with reminders 60, 30, 7 and 1 day before expiry, plus immediate reports of any name-server change and of blocking statuses such as clientHold or serverHold. This covers TLDs whose registry publishes an RDAP service, which is the vast majority of common ones. See domain expiry monitoring.

A single table lists every certificate and domain deadline, sorted by urgency, and the deadlines also appear in monthly reports. Reminders reach you on the alert channel of your choice, and your quiet hours hold them back until the end of the window you set, while real outages always get through.

In short

Certificate and domain expiries are almost never a technical surprise; they are an organisational problem: a task that fails silently, a forgotten reload, an account in the wrong person's name. Check by hand with openssl and RDAP when in doubt, then automate with staggered reminders and an up-to-date inventory. LucidStack does this for every HTTPS monitor you create, with no extra configuration.

Start monitoring in two minutes.

Add a URL, choose where to be alerted. LucidStack takes care of the rest, day and night.