SSL certificate expired and the website says 'Not Secure': how to fix it
First, confirm it really is expiry
"Not Secure" can mean several different things. Check which one you have before you change anything:
- Full-page warning with
NET::ERR_CERT_DATE_INVALID(Chrome), or "certificate expired" (Firefox, Safari): the certificate has expired. This page is for you. NET::ERR_CERT_COMMON_NAME_INVALID: the certificate doesn't cover this hostname. A common example iswwwmissing from the certificate.- No full-page warning, but "Not Secure" in the address bar: usually the page is loaded over plain
http://, or the page includes insecure (mixed) content. That's a different fix. - Only one person sees it: check the clock on their device before anything else.
Confirm from a terminal:
`bash
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -enddate -issuer
`
The issuer tells you who issued the certificate, for example Let's Encrypt, Sectigo or a cPanel AutoSSL provider. That tells you where to go next.
Step 1: Find where the certificate is managed
| Issuer / setup | Where to renew |
|---|---|
| Shared hosting with cPanel AutoSSL | cPanel → SSL/TLS Status |
| Let's Encrypt on your own server | Certbot (or another ACME client) on the server |
| Cloudflare edge certificate | Cloudflare dashboard → SSL/TLS → Edge Certificates |
| Paid certificate (bought from a CA or reseller) | Reissue or renew with the vendor, then install |
| Managed platform (e.g. a hosted WordPress or site builder) | The platform's support or domain settings |
Step 2: Renew
cPanel AutoSSL: open SSL/TLS Status, select the domains and click Run AutoSSL. If a domain fails, the status page shows a reason. The most common one is that DNS doesn't point at this server.
Certbot:
`bash
sudo certbot renew --cert-name example.com
sudo systemctl reload nginx # or apache2 / httpd
`
If it fails, run sudo certbot renew --dry-run -v to see the full error.
Paid certificate: create a new CSR, complete validation with the vendor, then install the new certificate with its intermediate chain. If the chain is missing, some browsers and most API clients will still fail even though the certificate itself is valid.
Cloudflare: edge certificates normally renew on their own. If the browser error shows an expired *origin* certificate, renew the certificate on your server, or install a Cloudflare Origin CA certificate there.
Step 3: Verify
- Run the
opensslcommand again and check the newnotAfterdate. - Test
wwwand the bare domain separately. - Load the site in a private window. If you reloaded the web server and still see the old certificate, another server or load balancer is serving it.
- Because of HSTS, visitors to sites that use it can't click past the warning at all. Once the site serves a valid certificate it will load normally again; visitors don't need to do anything.
Step 4: Find out why auto-renewal failed
If you skip this step, it will happen again at the next renewal. Common causes:
- DNS moved. The domain now points at a CDN or a new host, so the old server can't pass the HTTP challenge.
- The challenge path is blocked. A redirect rule, security plugin,
.htaccessrule or firewall blocks/.well-known/acme-challenge/. - A CAA DNS record doesn't allow the CA that's trying to issue.
- The renewal job isn't running. Check with
systemctl list-timers | grep certbotor look in the crontab. - Renewed but not reloaded. The new file is on disk, but the web server is still serving the old certificate from memory. Add a deploy hook:
--deploy-hook "systemctl reload nginx". - Card or account expired for a paid certificate or hosting plan.
Step 5: Make sure you hear about it next time
Renewals are getting more frequent. The CA/Browser Forum's ballot SC-081 caps public certificate lifetimes at 200 days from March 15, 2026, 100 days from 2027 and 47 days from 2029 (DNSimple). Let's Encrypt no longer sends expiry reminder emails. So add an outside check:
- a daily job that alerts when any certificate has fewer than about 21 days left. Auto-renewal normally runs well before that, so an alert means renewal has failed;
- alerts sent to a shared channel, not one person's inbox;
- every client hostname on the list, including
www, subdomains and mail.
The openssl -checkend flag makes a one-line check: it exits non-zero if the certificate expires within the given number of seconds.
A note for agencies
If this happened on a client site, it will probably happen on another one. We're building Lapsewatch, which will keep one list of every client domain with days-to-expiry and send an email or Slack alert before any certificate lapses. It isn't live yet; the page below explains what's coming.