Article

How to Fix an Expired SSL Certificate

An expired SSL certificate makes every browser block the site with a security warning. Fix it by renewing the certificate with your CA and reinstalling it on the server, then automate renewal so it can't lapse again. With certificate lifetimes shrinking to 47 days by 2029, automation is no longer optional.

By Paul Rudenko, Security ResearcherUpdated Jun 26, 20268 min read

An expired SSL certificate makes every browser block the site with a security warning. Fix it by renewing the certificate with your CA and reinstalling it on the server, then automate renewal so it can't lapse again. With certificate lifetimes shrinking to 47 days by 2029, automation is no longer optional.

What does an expired certificate do?

A TLS certificate is valid only between two dates — a "not before" and a "not after" timestamp baked into the certificate itself. The moment the clock passes the "not after" date, the certificate is expired, and every modern browser treats the connection as untrusted.

There is no grace period and no soft warning: Chrome, Firefox, Edge, and Safari all replace your page with a full-screen interstitial before any content loads.

In Chrome the visitor sees "Your connection is not private" with the subcode NET::ERR_CERT_DATE_INVALID under Advanced. Other browsers show their own wording for the same condition. The effect is the same everywhere — the site is effectively offline.

Search crawlers that hit an expired certificate may drop the page, and any API or webhook that calls your domain over HTTPS will fail its TLS handshake. An expired certificate is not a cosmetic problem; it is a full outage for anything that depends on the hostname.

The cause is almost always mundane: a renewal that was supposed to happen automatically didn't, or a manual certificate that nobody remembered to replace. The fix is equally concrete, and it splits cleanly by who you are.

If you're just visiting

If you landed here because a site you wanted to read is showing this warning, the short answer is that you cannot fix it. The certificate lives on the site's server, and only the people who run that server can renew it. Nothing you change in your own browser will make a genuinely expired certificate trusted again.

Before assuming the site is at fault, rule out the one local cause: your own device clock. A TLS certificate is judged against your computer's current time, so if your clock is set days or years off, a perfectly valid certificate looks expired and you get the same warning on every HTTPS site at once.

Turn on automatic date and time in your system settings and reload. If the warning only appears on one site, the problem is on their end.

When it is genuinely the site's certificate, the most useful thing you can do is tell the owner — a quick note saying "your SSL certificate expired and the site is showing a security warning" is often the first they hear of it. In the meantime, never click Proceed to bypass the warning on a page where you would log in or enter a card number. The block exists precisely because the connection can no longer be verified.

If you own the site

Your certificate has expired and visitors are being turned away. The fix is three steps — renew, reinstall, verify — followed by the step that actually matters long term: automate so this never happens again.

1. Renew the certificate

If you use a free, automated CA such as Let's Encrypt, renewal is a single command. Certbot will request a fresh certificate, prove control of the domain, and write the new files to disk:

# Let's Encrypt via certbot — renew now
sudo certbot renew --force-renewal

# or issue/renew for a specific host
sudo certbot certonly --nginx -d example.com -d www.example.com

If you bought a certificate from a commercial CA (DigiCert, Sectigo, GlobalSign and the like), log in to their dashboard, renew the order, and complete domain validation. They will re-issue the certificate, which you then download as a leaf certificate plus an intermediate (chain) bundle. Keep your existing private key, or generate a new key and CSR if the CA requires one.

2. Reinstall on the server

A renewed certificate does nothing until the web server is pointed at the new files and reloaded. For nginx, the certificate directives reference the full chain (your leaf plus the intermediates) and the private key:

# nginx — point at the new files, then reload
server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;  # leaf + intermediates
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}

# test config, then reload (no downtime)
sudo nginx -t && sudo systemctl reload nginx

For Apache, the equivalent directives live in your SSL virtual host:

# Apache (httpd-ssl.conf or the vhost)
SSLEngine on
SSLCertificateFile      /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

# test config, then reload
sudo apachectl configtest && sudo systemctl reload apache2

3. Verify from outside

Always confirm the fix from somewhere other than the server itself, because local caches and trust stores can mask a problem visitors still see. Check the new expiry date and that the full chain is being served:

# show the dates the live server is presenting
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -dates

The notAfter line should now be in the future. If it still shows the old date, the server is serving a cached or stale certificate — see the gotcha below.

4. Automate renewal — the step that matters

Renewing by hand is exactly how you got here. The durable fix is to make renewal automatic and to alert yourself if it ever fails. Certbot installs a systemd timer (or cron job) that attempts renewal twice a day and only acts when a certificate is within 30 days of expiry. Confirm it is active and use a deploy hook so the web server reloads automatically the moment a new certificate lands:

# confirm the renewal timer is running
systemctl list-timers | grep certbot

# dry-run the whole renewal path without changing anything
sudo certbot renew --dry-run

# reload the server automatically after every successful renewal
sudo certbot renew --deploy-hook "systemctl reload nginx"

Automation is no longer a nice-to-have. The CA/Browser Forum's ballot SC-081 sets a schedule that cuts the maximum validity of a public TLS certificate to just 47 days by 15 March 2029. At that length a certificate must be renewed roughly eight times a year — a cadence no team can reliably hit by hand.

And the problem is already widespread: AppViewX reports that up to 25% of TLS certificates are expired at any given time. Treat the timer plus a deploy hook as the real fix; the renewal you ran above is only the emergency patch.

Want to check your certificate's expiry and chain right now?

Check your certificate

For peace of mind beyond a single check, add ongoing monitoring so an expiring certificate pages you before browsers do. A scheduled full scan watches your certificate's expiry date (and the rest of your TLS configuration) continuously, so a stalled renewal becomes an alert in your inbox rather than an outage your customers report.

Why does the site still show expired after I renewed?

The most common reason a site still shows an expired certificate after you renewed it is that the new certificate was never actually served. Renewing writes new files to disk, but the running web server keeps the old certificate in memory until you reload it — so always finish with systemctl reload nginx (or the Apache equivalent). Even then, a CDN, load balancer, or reverse proxy sitting in front of your origin may hold its own copy of the certificate and keep serving the expired one from cache. If openssl shows a fresh date at the origin but visitors still see the warning, renew or update the certificate at the edge (Cloudflare, Fastly, your ALB) too, and clear its TLS cache. The certificate is only fixed once every layer that terminates HTTPS is serving the new one.

Once the new certificate is installed at every layer and automated renewal is verified, an expired-certificate outage stops being a recurring emergency and becomes something you simply don't think about again.

For the wider context, see the pillar guide to SSL/TLS errors, and for the specific Chrome warning an expired certificate produces, read how to fix NET::ERR_CERT_DATE_INVALID.

Frequently asked questions

How do I renew an expired SSL certificate?

It depends on who issued it. If you use Let's Encrypt or another automated CA, run a single command — certbot renew --force-renewal — and certbot requests a fresh certificate, proves control of your domain, and writes the new files to disk. If you bought a certificate from a commercial CA such as DigiCert or Sectigo, log in to their dashboard, renew the order, complete domain validation, and download the re-issued leaf certificate plus its intermediate chain. In both cases the renewal is only half the job: you must then point your web server at the new files and reload it, because the running server keeps serving the old certificate from memory until it is reloaded. Finish by verifying the new expiry date from outside your own machine so caches don't hide a problem visitors still see.

Why did my auto-renewal fail?

Auto-renewal usually fails for one of a handful of reasons. The most common is a broken domain-validation challenge: certbot's HTTP challenge needs port 80 reachable and the /.well-known/acme-challenge path served, so a firewall change, a redirect, or a moved web root will block it. A revoked or rate-limited account, an expired email registration, or a CA outage can also stop renewal. Sometimes the certificate renews fine but the web server is never reloaded, so the old one keeps being served. Run sudo certbot renew --dry-run to reproduce the failure safely without touching your live certificate — it exercises the entire renewal path and prints the exact error. Then check the renewal logs, confirm the timer is active with systemctl list-timers, and add a --deploy-hook so the server reloads automatically once renewal succeeds.

How long are SSL certificates valid now?

As of 2026 a newly issued public TLS certificate is valid for a maximum of about 398 days, but that ceiling is dropping fast. The CA/Browser Forum's ballot SC-081 sets a phased schedule that reduces the maximum validity in stages — to 200 days, then 100 days, and finally to just 47 days by 15 March 2029. At 47 days a certificate has to be renewed roughly eight times a year. Shorter lifetimes limit the damage a compromised or mis-issued certificate can do and force domain re-validation more often, which is good for security but impossible to keep up with by hand. This is why every CA and browser vendor is steering operators toward fully automated issuance and renewal: manual processes simply cannot sustain a renewal every six or seven weeks across a real fleet of domains.

How do I stop certificates from expiring?

Automate renewal and add independent monitoring — never rely on a human remembering a date. With Let's Encrypt, certbot installs a systemd timer or cron job that checks twice a day and renews any certificate within 30 days of expiry; confirm it is active with systemctl list-timers and validate the path with certbot renew --dry-run. Attach a --deploy-hook that reloads your web server automatically so a renewed certificate is actually served. For commercial certificates, use your CA's ACME endpoint or auto-renew feature where available. Crucially, layer on external monitoring that watches the expiry date your live server presents and alerts you well before the deadline — that catches the cases where renewal silently fails or a CDN keeps serving a stale certificate. Together, automated renewal plus expiry monitoring turn a recurring outage into a non-event.

Related guides

See your whole external attack surface

One page is a start. The full external scan covers TLS, headers, DNS, exposed files, open services and known-exploited CVEs across your whole domain.

See the full scan →