The Real Challenges of Managing Certificates on Web Servers: Nginx, Apache, and Tomcat
Issuing a certificate is the easy part. What breaks sites in production is what happens afterward: installing the certificate on the web server, assembling the chain correctly, and — the most underestimated of all — actually getting the server to serve the new certificate.
Every web server has its own set of traps. What works on Nginx doesn't apply to Tomcat. What's standard on Apache changed between versions. And many of these problems produce no error at renewal time — they surface later, when a customer reports the site is "not secure" and you discover the new certificate was never actually served.
This article gathers the concrete problems infrastructure teams face on each server, based on real, documented incidents.
Nginx: the certificate renews, but the server keeps serving the old one
This is probably the most common and most treacherous problem of all. Certbot runs, the new file is written to disk, the renewal script reports success — and Nginx keeps presenting the old certificate.
The cause is architectural. Nginx loads certificates at the moment it parses the configuration. Workers present whatever the master process loaded at startup or during the last reload. Replacing the PEM file on disk does not change what active workers present — only a reload or restart pulls the new material into memory.
The detail that catches many people: if the config line pointing to the certificate doesn't change, Nginx won't reload the certificate. The old file at the path is overwritten by the new one, but the server keeps using the certificate from memory. In some environments, administrators reported that neither nginx -s reload, nor systemctl reload nginx, nor /etc/init.d/nginx reload loaded the new certificate — only a full restart of the service fixed it.
There's also a silent aggravating factor: if a reload fails, Nginx keeps serving with the previous configuration, which still holds the expired certificate. And because old workers continue until their connections drain, even after a successful reload long-lived connections may briefly present the old certificate.
The practical result: you think you renewed, your file monitoring says the certificate on disk is new, and users still see an expired certificate. Without a check that compares what's being served (not what's on disk), that gap goes unnoticed until it becomes an incident.
Apache: the intermediate chain and the change that broke configs
Apache's number one problem isn't the certificate itself — it's the chain. The most frequent SSL misconfiguration is a missing intermediate certificate: the leaf certificate is installed, but the CA intermediate isn't being served alongside it.
What makes this error dangerous is that it doesn't show up for you. Desktop browsers often cache intermediates — if a previous site used the same intermediate CA, the browser already has it and won't notice yours is missing. But mobile browsers don't cache: iOS Safari, Chrome on Android on a fresh install, and most mobile clients fail immediately if the intermediate is missing from the server's response. In other words: it works in your Chrome, breaks on the customer's phone.
To make it worse, the correct way to configure this changed between Apache versions. Starting with Apache 2.4.8, the SSLCertificateChainFile directive was deprecated. The recommended modern approach is to include the intermediate certificates directly in the file specified by the SSLCertificateFile directive, concatenating leaf + intermediates. Configs written for old versions, copied to new servers, silently stop loading the chain — in newer versions, Apache may simply ignore SSLCertificateChainFile and load only what's in SSLCertificateFile.
And there's the ordering trap. A common mistake is placing the certificates in reverse order (root first, leaf last). This doesn't work: the leaf must always come first. A chain file assembled in the wrong order produces a config that looks correct but serves an invalid chain.
Tomcat: the Java world has its own rules
If you come from Nginx and Apache, Tomcat is another planet — because it doesn't work with loose PEM files, but with keystores. Tomcat operates only on JKS, PKCS11, or PKCS12 format keystores. JKS is Java's standard "Java KeyStore" format, created by the keytool tool. PKCS12 is an internet standard, manipulable via OpenSSL, among others.
This creates an entire class of problems that doesn't exist on the other servers:
Keystore type mismatch. A classic error: generating the keystore in PKCS12 but Tomcat expecting JKS (or vice versa). The historical symptom is Tomcat failing to start with a java.io.IOException. In one documented case, the fix was precisely that the default keystore type was set to JKS in java.security, while the keystore in use was PKCS12 — aligning the two was enough to make it work.
Chain inside the keystore. In Tomcat, the intermediates need to be inside the keystore, not in a separate file. When generating the PKCS12 via OpenSSL, omitting the -chain flag produces a keystore without the complete chain — and the server starts, but serves an incomplete chain, reproducing the same Apache problem by a different route.
Alias sensitivity. Each entry in the keystore is identified by an alias string. Although many implementations treat aliases case-insensitively, some are case-sensitive — PKCS11, for example, requires case-sensitive aliases. For that reason it's not recommended to use aliases that differ only in case.
The result is that renewing a certificate on Tomcat isn't "replacing a file." It's rebuilding a keystore with the right format, the right chain, and the right alias, then restarting the service — a process with far more failure points than the cp + reload of the other servers.
The common pattern: renewing is not the same as deploying
Notice what the three cases have in common. In none of them was the problem obtaining the certificate. The problem was delivering it correctly to the server and getting the server to use it:
- On Nginx, the certificate was on disk but not in memory.
- On Apache, the certificate was right but the chain was incomplete or badly ordered.
- On Tomcat, the certificate needed to be in the format and structure Java demands.
Multiply that by a real infrastructure, with dozens of heterogeneous servers — some Nginx, some Apache of different versions, some Tomcat — and by a renewal cycle that, with the SC-081 ballot, will reach eight renewals per year per certificate by 2029. Manual management, server by server, with a different procedure for each, doesn't scale.
What this demands from an automation strategy
Automating issuance solves half the problem. The other half — the one that actually takes sites down — is deployment. A certificate deployment strategy that handles these cases needs to:
Know each server's specifics. Write fullchain for Nginx, concatenate correctly for Apache 2.4.8+, rebuild the keystore with the correct format and alias for Tomcat. A "generic deploy" that treats every server the same reproduces exactly the bugs above.
Reload the service the right way. Copying the file isn't enough. Each server has its own mechanism — and in Nginx's case, knowing when a reload isn't enough and a restart is required.
Verify what's being served, not what's on disk. Validation needs to open a TLS connection and confirm that the presented certificate is the new one and that the chain is complete — the only way to catch the "renewed but didn't reload" gap.
Discover where the certificates actually are. You can't automate deployment on servers you don't know exist. Continuous discovery is the prerequisite for any reliable automation.
The end goal is simple to state and hard to do by hand: that a certificate renewal arrives, correctly formatted and actually loaded, at every endpoint that consumes it — whether an Nginx, an Apache, or a Tomcat — without manual intervention and without the late discovery that the site is down.
Frequently asked questions
Why did my certificate renew but the browser still shows the old one (or shows it as expired)?
On Nginx and several other servers, the certificate is loaded into memory when the configuration is parsed. Replacing the file on disk doesn't change what active workers present — you need a reload (or, in some cases, a full restart) for the server to load the new material. If the reload didn't happen or failed, the server keeps serving the old certificate even with the new file on disk.
Why does the site work in my browser but throw a certificate error on mobile?
It's almost always an incomplete chain: the intermediate certificate isn't being served. Desktop browsers frequently cache intermediates from previous visits and "hide" the problem, while mobile browsers don't cache and fail immediately. The fix is to make sure the server serves the leaf followed by the intermediates, in the correct order.
Why is renewing a certificate on Tomcat more complicated than on Nginx or Apache?
Because Tomcat uses keystores (JKS or PKCS12) instead of loose PEM files. Renewing requires rebuilding the keystore with the correct format, including the chain inside it, and using the correct alias, plus restarting the service. That's more steps and more failure points than the simple file replacement of the other servers.
Doesn't issuance automation (ACME/certbot) solve all this on its own?
No. ACME clients handle issuance and renewal very well, but correct deployment on each server type — format, chain, proper reload, and verification of what's actually being served — is a separate step. It's precisely at that deployment step, not the issuance step, where most certificate incidents happen.
See the technical documentation
Integration guides, API and automation at docs.pkiless.com.
Automate your certificate lifecycle
Discovery, renewal and deployment automated — ready for 47-day validity.
Try PKILESS for free