Skip to content
ohsudo, Home
Security

"Certificate has expired": check the dates, renew it, and find out why it didn't renew

Fix "certificate has expired" and NET::ERR_CERT_DATE_INVALID: check the dates with openssl, renew with Certbot, reload the server, and fix why renewal or clock failed.

Beginner4 min readApplies to Let's Encrypt · Certbot · Nginx · Apache · curl · OpenSSL 1.1+

by OhSudo ··

Not sure this is your cause?Find it step by step: Website down →

Part of a learning path:Web servers: nginx and HTTPS in production

In a browser:

Your connection is not private
NET::ERR_CERT_DATE_INVALID

From curl or code:

curl: (60) SSL certificate problem: certificate has expired

TLS certificates have a validity period, and today falls outside it. Either the certificate really has expired, or the machine asking has the wrong date, or it’s an intermediate certificate that’s expired rather than yours. It takes one command to tell which, and it’s worth fixing why it didn’t renew too, or you’ll be back here in 90 days.

  1. Clienttoday's date, by its own clock
  2. CertificatenotBefore … notAfter
  3. Outside that periodcertificate has expired(breaks here)
Today falls outside the certificate's validity period. Either it really expired, the client's clock is wrong, or an intermediate in the chain expired rather than yours.

TL;DR

Terminal window
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -subject
date -u
sudo certbot renew
sudo systemctl reload nginx

1. Check the dates

Ask the server what it’s serving:

Terminal window
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -subject -issuer
notBefore=Aug 1 09:12:45 2026 GMT
notAfter=Oct 30 09:12:44 2026 GMT
subject=CN=example.com
issuer=C=US, O=Let's Encrypt, CN=E7

Now compare with the clock on the machine showing the error:

Terminal window
date -u
What you find Cause Go to
notAfter is in the past It really expired Section 2
The date is right, and the file on disk is newer The server wasn’t reloaded Section 3
The date on your machine is wrong The clock Section 4
Only some clients fail An old client, or chain Section 5

-servername matters: a server with several sites gives you the wrong certificate without it. To read a long date as a timestamp, or the reverse, use the Timestamp Converter.

2. Renew it

With Let’s Encrypt:

Terminal window
sudo certbot certificates
sudo certbot renew

The first shows every certificate and its expiry date. If renewal fails, the message says why: see Certbot failed to authenticate. Port 80 closed by a recent firewall change is a common one.

A certificate from a commercial authority has to be renewed with them, and the new files then installed by you.

3. Reload the server

This one catches people. A server reads its certificate at startup, and it keeps serving the old one until it’s told otherwise. So the file is new, and visitors still get an expired certificate:

Terminal window
sudo openssl x509 -noout -enddate -in /etc/letsencrypt/live/example.com/fullchain.pem
sudo nginx -t && sudo systemctl reload nginx

Make it automatic, so that it doesn’t happen again. Certbot runs anything in this folder after a successful renewal:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh <<'EOF'
#!/bin/sh
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

Other programs hold a copy too, such as HAProxy, mail servers, and databases. And check which file your config really uses:

Terminal window
sudo nginx -T 2>/dev/null | grep -E 'server_name|ssl_certificate '

4. A wrong clock

If date shows the wrong year, then every certificate looks invalid, and yours isn’t the problem. It’s common on virtual machines, single-board computers with no battery, and containers on such hosts:

Terminal window
timedatectl
sudo timedatectl set-ntp true

On Windows, use w32tm /resync. A machine with a wrong clock often fails on apt as well, for the same reason.

5. Why didn’t it renew?

Find this out, or it comes back:

Terminal window
systemctl list-timers | grep -i certbot
sudo journalctl -u certbot -n 30 --no-pager
sudo grep -i error /var/log/letsencrypt/letsencrypt.log | tail -n 5
sudo certbot renew --dry-run

No timer means that nothing ever tried, as can happen with installs by hand, or in a container. A package normally sets this up, and otherwise you can add a cron job. See cron job not running if it’s there and doing nothing.

An expired intermediate. Your own certificate is fine, and one above it in the chain has expired, or an old client doesn’t trust the newer one. Use fullchain.pem, not cert.pem, in your config. An old system with outdated root certificates needs an update: sudo apt install --reinstall ca-certificates. See unable to get local issuer certificate.

6. Set up an alert

Certificates fail at the worst times, and it’s easy to notice in advance. This exits with an error if there are under 14 days left, which suits a monitoring check:

Terminal window
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -checkend 1209600

Certificates are also getting shorter lives, with public ones set to drop well below a year in the coming years. So renewal by hand is less and less practical, and automating it now is time well spent. The Nginx Config Generator includes the Certbot steps.

Warning

Don’t get around this with curl -k, verify=False or NODE_TLS_REJECT_UNAUTHORIZED=0, even “just for now”. That turns off the check that proves who you’re talking to, and such settings tend to stay in code for years. In a browser, don’t click through on a site that handles logins or payments.

Shell, we have a problem!

Similar, but different: unable to get local issuer certificate is a missing part of the chain. ERR_CERT_COMMON_NAME_INVALID means the certificate is for another name. self-signed certificate means it wasn’t issued by a trusted authority. wrong version number usually means you’re speaking TLS to a port that’s plain HTTP. Certbot failed to authenticate is about getting one.

Found this useful? Share it.

Found a mistake? Let us know at contact@ohsudo.com.

Tools

Try it yourself

Articles

Related articles