Fixing SSL certificate errors on your website
What this is
Visitors see "Your connection is not private" (or the padlock is broken) on your site. The browser's error code tells you which of the distinct problems you have, so start by reading it, then this page fixes each one.
ERR_CERT_DATE_INVALID, the certificate expired. By far the most common, and almost always a silent renewal failure (below).ERR_CERT_COMMON_NAME_INVALID, a name mismatch: the certificate served doesn't cover the hostname in the address bar.ERR_CERT_AUTHORITY_INVALID, the certificate isn't from a trusted authority: a self-signed or default certificate is being served instead of your real one.ERR_TOO_MANY_REDIRECTS, not a certificate problem at all: almost always the Cloudflare Flexible mode loop (below).
See what's actually being served
Don't guess, ask the server:
echo | openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates -subject -issuer
That prints the certificate's validity dates, what names it was issued for, and who issued it, which usually settles the "which problem is this" question on the spot. For the full third-party view:
- SSL Labs' server test, the complete grade: certificate, chain validation, protocols, and exactly what's wrong, the single best tool here.
- crt.sh, the public log of every certificate issued for your domain, useful to confirm whether a renewal actually happened.
- Why No Padlock, for the mixed-content case at the bottom.
The day-91 story: renewals fail silently
Let's Encrypt certificates live 90 days. certbot installs a timer that renews them automatically, and when that timer breaks, nothing complains, until day 91, when the site goes red for every visitor at once. If your certificate expired, don't just renew it once, find out why automation failed or you'll be back in 90 days:
certbot renew --dry-run
systemctl list-timers | grep certbot
The dry run either passes (automation is healthy again) or prints the actual reason it can't renew. The common ones:
- Port 80 closed. The default HTTP-01 validation requires Let's Encrypt to reach
http://yourdomain/.well-known/acme-challenge/. If your own firewall grew a rule blocking 80, renewal dies:ufw allow 80/tcp. (Our managed firewall never blocks web ports.) - DNS changed since issuance. The domain no longer points at this VPS, or, the sneaky one, a stale AAAA (IPv6) record points somewhere else: validators may prefer IPv6, reach the wrong machine, and fail while the site "works fine" for you over IPv4. Check with
dig +short yourdomain.com A yourdomain.com AAAAagainst where your DNS should point. - Web-server config drift: a rewrite/redirect added since issuance now swallows
/.well-known/acme-challenge/. Make sure that path is served plainly. - Rate limits: repeated failed attempts can hit Let's Encrypt's limits; fix the underlying cause first, then use
--dry-run(which uses the staging environment) to verify before real attempts.
Name mismatches
The certificate works, just not for the name being visited:
wwwvs the bare domain: the cert covers one but not the other. Reissue covering both:certbot --nginx -d yourdomain.com -d www.yourdomain.com.- A new subdomain isn't on the certificate, issue for it (or use a wildcard via DNS validation).
- nginx is serving the wrong site's certificate: with multiple vhosts, a request that matches no
server_namegets thedefault_server's cert. Check which server block actually catches the hostname.
"I renewed, but the browser still shows the old certificate"
Web servers load certificates at startup. A renewed file on disk changes nothing until nginx/Apache reloads (systemctl reload nginx). certbot's standard setup does this via a deploy hook, if yours didn't, add one, or you'll do this dance every 60 days.
Broken chain: "works in my browser, fails for my users"
If browsers are fine but API clients, mobile apps, or older devices report an untrusted certificate, your config likely points at the bare certificate instead of the chain. With certbot files: ssl_certificate must reference fullchain.pem, not cert.pem. SSL Labs flags this as "chain issues", and it's a one-line fix plus a reload.
Cloudflare SSL modes, get this one setting right
If your site is behind Cloudflare, the SSL/TLS mode (Cloudflare dashboard → SSL/TLS) decides how the Cloudflare-to-origin leg works, and the wrong mode produces exactly the errors on this page:
- Off: no HTTPS at all. Don't.
- Flexible: visitors get HTTPS to Cloudflare, but Cloudflare talks plain HTTP to your VPS. No certificate needed on the origin, which is why people pick it, but the origin leg is unencrypted, and if your VPS also redirects HTTP→HTTPS (most setups do), you get the infamous redirect loop (
ERR_TOO_MANY_REDIRECTS). Avoid. - Full: Cloudflare connects to your origin over HTTPS but accepts any certificate, even expired or self-signed. Encrypted, but not authenticated, a stopgap, not a destination.
- Full (strict): Cloudflare requires a valid certificate on your origin. This is the correct setting. Satisfy it either with your normal certbot certificate, or with a free Cloudflare Origin CA certificate (issued in the dashboard, valid up to 15 years, trusted only by Cloudflare, perfect when the site is always proxied).
Debugging note: with the proxy on, the certificate visitors see is Cloudflare's edge certificate, not yours. To inspect what your origin itself serves, test it directly: curl -kIv https://YOUR.VPS.IP -H "Host: yourdomain.com", the same isolation trick as in the 502 guide.
Mixed content: padlock present, but "not secure" warnings
If the certificate is fine but the padlock shows warnings (or images/scripts don't load), the page is loading some assets over plain http://. The browser console lists every offender, and Why No Padlock does it in one paste. On WordPress, setting the site URL to https:// fixes most of it; hardcoded http:// links in themes and databases account for the rest.
Using Caddy?
Caddy issues and renews automatically by design, so a certificate failure there almost always reduces to the same two causes: port 80/443 reachability or DNS not pointing at the VPS. Its logs (journalctl -u caddy) name the ACME error directly.
Verify, then stop worrying
After any fix: reload the web server, hit the site in a private window, and run SSL Labs once, a clean A means certificate, names, and chain are all right. Then confirm certbot renew --dry-run passes so day 91 never comes back.
Still need help?
You can open a support ticket. So we can help on the first reply, it's worth mentioning:
- the domain and the exact browser error code,
- what
certbot renew --dry-run(or your ACME client's log) says, - whether the site is behind Cloudflare, and which SSL mode if so.
Related questions
- "Why does my site say your connection is not private?"
- "My Let's Encrypt certificate expired, why didn't it renew?"
- "How do I check what certificate my server is serving?"
- "The certificate works for my domain but not www (or a subdomain)."
- "I renewed the certificate but browsers still show the old one."
- "Which Cloudflare SSL mode should I use, Flexible, Full, or Full (strict)?"
- "Why do I get too many redirects with Cloudflare?"
- "Why does my API client reject my certificate when browsers accept it?"