Back to blog

SSL certificate expired - what to do

· 6 min read

An expired SSL certificate blocks access with an insecure-connection warning and conversions drop to zero. What to do right away and how to prevent it.

SSL certificate expired - what to do

What the visitor sees

An expired certificate triggers a full-screen browser warning:

  • Chrome / Edge: "Your connection is not private" (NET::ERR_CERT_DATE_INVALID)
  • Firefox: "Warning: Potential Security Risk Ahead" (SEC_ERROR_EXPIRED_CERTIFICATE)
  • Safari: "This Connection Is Not Private"

A regular visitor clicks "Back". The vast majority of organic traffic simply leaves. Search engine crawlers (Googlebot, Bingbot) stop indexing and after a few days you start losing positions in search.

What to do if it expired right now

  1. Identify who issued the cert. In the terminal: openssl s_client -connect mywebsite.com:443 -servername mywebsite.com < /dev/null 2>/dev/null | openssl x509 -noout -issuer -dates
  2. Let's Encrypt (free, 90-day validity): typically via certbot renew or via the hosting panel (One-click renewal).
  3. Commercial cert (DigiCert, Sectigo, GlobalSign): log into the issuer's admin panel, generate a new CSR and complete domain validation (DNS TXT record or email).
  4. Deploy the new cert to the reverse proxy (nginx, Caddy, Traefik) and restart or reload the process.
  5. Verify via SSL Labs or our SSL check tool that the cert is served correctly and the certificate chain is complete.

Heads up: Don't forget the intermediate cert - without it modern browsers can pull the chain via AIA, but older clients and some API libraries will fail.

Automatic renewal: Let's Encrypt + certbot

The simplest prevention is to fully automate renewal. A Let's Encrypt cert renews every 90 days via certbot:

# /etc/cron.d/certbot-renew
0 3 * * * root certbot renew --quiet --deploy-hook "systemctl reload nginx"

This cron runs daily at 3:00 AM. Certbot internally checks whether the cert is approaching expiry (when less than a third of its lifetime remains, which for a 90-day Let's Encrypt cert works out to roughly 30 days before the end). If so, it renews the cert and reloads nginx on success. Otherwise it does nothing.

Caddy and Traefik: fully automatic

If you use Caddy or Traefik as your reverse proxy, the ACME challenge is built directly into the binary. You just mark the domain in the config and the server requests and renews the cert by itself:

# Caddyfile
mywebsite.com {
  reverse_proxy localhost:3000
}

No certbot, no cron. Caddy calls the Let's Encrypt API in the background and manages the entire renewal cycle.

Commercial certs: 1-3 year validity

In March 2025 the CA/B Forum voted to gradually shorten the lifetime of SSL certificates. Since March 2026 the maximum lifetime is 200 days (previously 398). In March 2027 it drops to 100 days and in March 2029 to 47 days (CA/B Forum SC-081). Despite this, some companies still prefer commercial CAs, for these reasons:

  • Extended Validation (EV) shows the organization in the address bar (Chrome has stopped displaying it prominently since 2019).
  • Wildcard for many subdomains although Let's Encrypt now supports wildcards via DNS-01.
  • Warranty financial liability of the CA in case of compromise.
  • Compliance / audit some industries have external requirements.

For most sites Let's Encrypt or another free CA (ZeroSSL, Buypass) is enough.

Expiry monitoring as a safety net

Even if you have automatic renewal, expiry monitoring works as insurance. Renewal can fail because of:

  • a rate limit from the CA (Let's Encrypt: 5 duplicates / 7 days)
  • a DNS change that breaks the ACME challenge
  • a firewall rule blocking port 80 (HTTP-01 challenge)
  • a crash of certbot or the cron that nobody noticed

ePulz.io tracks the expiry of every monitored endpoint and sends an alert 30, 14, 7, 3 and 1 day before expiry. One green signal that the cert renewed in time - and you have certainty that the automation works.

Expiry is not the only SSL failure

"Expired" is the failure everyone knows, but a TLS handshake can break in several other ways, and each shows the visitor a near-identical scary warning:

Problem Browser error Typical cause
Expired NET::ERR_CERT_DATE_INVALID Renewal didn't run
Not yet valid NET::ERR_CERT_DATE_INVALID Server clock is wrong / cert issued for the future
Name mismatch NET::ERR_CERT_COMMON_NAME_INVALID Cert is for www but served on the apex (or vice versa)
Incomplete chain NET::ERR_CERT_AUTHORITY_INVALID Intermediate cert missing
Self-signed NET::ERR_CERT_AUTHORITY_INVALID A staging cert leaked into production
Wrong host on shared IP varies SNI misconfiguration on the reverse proxy

A monitor that only watches the expiry date will miss the name mismatch and the missing intermediate entirely. Real SSL monitoring validates the whole handshake, not just one date field. You can run the same validation manually any time with our SSL check tool.

Why the certificate lifetime keeps shrinking

The shortening from 398 days down to 47 (CA/B Forum SC-081) is not arbitrary. Shorter lifetimes limit the damage window if a private key is compromised, and they force automation: a 47-day certificate that you renew by hand is simply not viable, so operators are pushed toward ACME. The practical takeaway is blunt - by 2029, manual renewal is effectively dead. If you are still clicking through a CA dashboard once a year, plan the move to automated issuance now, while the deadlines are years out rather than weeks.

One domain, many certificates

Most real outages happen on a subdomain nobody was watching. A single company easily runs separate certificates for www, api, mail, status and a handful of customer-facing subdomains, often issued by different tools on different schedules. The apex renews fine via Caddy; the api host still has a hand-installed commercial cert from two years ago that quietly lapses. The fix is to inventory every hostname that terminates TLS and monitor each one independently. Do not assume that because the homepage is green, the API your mobile app depends on is too. If you are unsure which hostnames even exist, a DNS lookup of your domain is a good starting point for finding the A and CNAME records you forgot about.

Wildcard, SAN and the trade-offs

  • Wildcard (*.example.com) covers any single-level subdomain with one cert. Convenient, but one private key now protects everything, and a compromise is broader. Let's Encrypt issues wildcards only via the DNS-01 challenge.
  • SAN (multi-domain) lists explicit hostnames in one certificate. More control, but you must reissue when you add a host.
  • Per-host certs are the most isolated and the easiest to automate with ACME, at the cost of more certificates to track. There is no universally correct choice; the more certificates you have, the more important monitoring becomes, because the human brain does not track 14 independent expiry dates.

Activate SSL monitoring

Alerts 30/14/7/3/1 days before expiry. No configuration, no DNS changes. 7 days free.

Start monitoring →

Share: Link copied

Try ePulz.io free - 7 days, no credit card needed.

Create account