Why the Browser Still Shows the Old Certificate After Renewal
Renewing a certificate is not the same thing as serving the renewed certificate.
That distinction causes a lot of operational confusion.
An ACME client can successfully obtain a fresh certificate while the browser still receives the old one. When that happens, the problem is usually in deployment, reload behavior, or TLS termination topology rather than in issuance itself.
The short explanation
If the browser still shows the old certificate after renewal, one of these is usually true:
- the server did not reload
- the active config still points to the wrong file path
- the wrong edge node or proxy is serving traffic
- the default HTTPS server is winning for that hostname
- a public layer is still serving a different certificate than the origin
The first operational fact that matters
Current Certbot documentation says servers should point directly to files under /etc/letsencrypt/live/$domain rather than copying certificate files elsewhere.
That matters because Certbot updates the live path during renewal.
If your deployment copied a certificate to some other location once and never updated that path again, the browser can keep seeing the stale certificate even though renewal itself succeeded.
The second fact that matters
Current Certbot documentation also explains that if you want a command to run only after a successful renewal, you should use a --deploy-hook.
This matters because many environments need an explicit reload or reload-like action after renewal:
- NGINX
- HAProxy
- reverse proxies
- application gateways
- custom PEM conversion pipelines
Without the right deploy step, a new certificate can exist on disk while the running service keeps the old certificate in memory.
The highest-value causes
1. No reload happened after renewal
This is the cleanest and most common cause.
The certificate renewed, but the TLS-serving process was never reloaded, restarted, or otherwise told to pick up the new files.
Certbot’s documentation is explicit that deploy hooks exist for exactly this kind of post-renew action.
2. The service is not using the live path
Certbot documents fullchain.pem as the file NGINX expects for ssl_certificate and privkey.pem for the key path.
If the service still points to:
- an older copied PEM
- a manually exported file
- a different certificate name
then renewal can succeed but the browser still receives the old certificate.
3. The wrong certificate is being selected for the hostname
A "stale certificate" symptom is not always about age.
Sometimes the browser is receiving the wrong certificate for the hostname because the default HTTPS server or the wrong virtual host is serving that connection.
That is why What Is SNI and Why a Server Serves the Wrong Certificate belongs in the same troubleshooting path.
4. The edge layer is different from the origin
If traffic terminates on a CDN, reverse proxy, load balancer, or ingress tier, that layer may still be serving the previous certificate even though the origin already has the renewed one.
This is a common cause of confusion when operators verify the origin host locally and assume the public site must now be fixed too.
5. The wrong certificate files were deployed
Certbot’s documentation distinguishes between:
cert.pemchain.pemfullchain.pem
For NGINX, it documents that fullchain.pem is the correct file for ssl_certificate.
Using the wrong file or a stale copied bundle can create certificate presentation issues even when renewal technically succeeded.
Why this problem often appears after "successful" automation
A renewal log can look healthy because the issuance step worked.
But the real user-visible chain depends on the whole deployment path:
- ACME client
- filesystem paths
- reload hooks
- active reverse proxy
- public edge node
If any one of those still points at older state, the browser result lags behind the renewal event.
What to check first
1. Check what certificate the public hostname actually serves
Do not stop at local filesystem inspection.
The public hostname result is the truth users see.
2. Check whether the service uses /etc/letsencrypt/live/...
If the service uses copied files or old export paths, fix that before doing anything else.
3. Check whether a deploy hook or equivalent reload action exists
Current Certbot documentation is clear that deploy hooks are the right place for post-renew actions that should happen only after successful renewal.
4. Check whether the edge and origin are the same place
If the domain sits behind a proxy or CDN, the certificate you fixed on the origin may not be the one the public still receives.
5. Check whether the hostname is hitting the right virtual host
If the wrong server block or default HTTPS server is winning, the issue may look like a stale certificate when it is actually a host-routing issue.
Why this matters for domain lookup
Domain lookup helps you understand whether the hostname resolves to:
- a CDN
- a reverse proxy
- a load balancer
- shared hosting or multi-tenant TLS infrastructure
That context changes the debugging path immediately.
If the domain does not resolve directly to the box where renewal ran, then "renewed on server A" is not enough evidence that public traffic is fixed.
The safest operational model
The cleaner model is:
- keep services pointed at the live certificate path
- reload only after successful renewal
- verify the public certificate after deployment
- monitor the public endpoint rather than trusting local logs alone
This is one of the reasons How to Monitor Certificate Expiration and Renewal Failures matters.
Common misunderstandings
"Certbot renewed successfully, so users must already have the new certificate"
No.
Issuance and public serving are different steps.
"The local server shows the new certificate, so the problem is browser cache"
Sometimes caching exists, but the higher-probability causes are wrong file paths, missing reloads, or a different edge layer serving the public hostname.
"Old certificate means renewal failed"
Not always.
Renewal may have succeeded while deployment drift kept the old certificate live.
FAQ
Why does the browser still show the old certificate after renewal?
Because the renewed certificate may not have been deployed, reloaded, or selected on the public traffic path that users actually hit.
What Certbot file should NGINX usually use?
Current Certbot documentation says NGINX should use fullchain.pem for ssl_certificate and privkey.pem for ssl_certificate_key.
Do I need a reload after renewal?
In many environments, yes. If the service keeps TLS material in memory or needs to reopen files, a successful renewal alone is not enough.
How do I avoid this in the future?
Point services at the live certificate paths, use deploy hooks for post-renew actions, and monitor the public hostname rather than trusting local renewal output alone.
Continue reading
Stay in the same investigation track with these closely related guides.
Tools mentioned in this article
Run the same diagnostics to follow along with the guide.