Tomcat typically loads SSL certificates during server startup through the keystoreFile
parameter in server.xml. The traditional approach requires a full server restart when certificates expire or need updating - an operation that causes service interruption.
Many production environments can't tolerate restarts for certificate updates. Through testing various Tomcat versions (8.5+), I've found these working approaches for dynamic reload:
Tomcat exposes the SSL Host Config through JMX. Here's a Java snippet to trigger reload:
// Requires catalina.jar in classpath import org.apache.tomcat.util.net.SSLHostConfig; import org.apache.tomcat.util.net.SSLHostConfigCertificate; MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("Catalina:type=ProtocolHandler,port=8443"); SSLHostConfig sslHostConfig = (SSLHostConfig)mbs.getAttribute(name, "sslHostConfig"); for (SSLHostConfigCertificate cert : sslHostConfig.getCertificates()) { cert.getCertificate().reload(); }
Create a watcher service that monitors keystore changes:
Path path = Paths.get("/path/to/keystore.jks"); WatchService watchService = FileSystems.getDefault().newWatchService(); path.getParent().register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); while (true) { WatchKey key = watchService.take(); for (WatchEvent<?> event : key.pollEvents()) { if (event.context().toString().equals("keystore.jks")) { // Trigger reload using Method 1's JMX approach } } key.reset(); }
- Works with Tomcat 8.5+ (tested up to 10.1)
- Requires JMX enabled in Tomcat (add
-Dcom.sun.management.jmxremote
to CATALINA_OPTS) - The new certificate must be valid - Tomcat won't reload invalid certs
- Consider file locking issues when replacing keystore
If using Tomcat's APR connector, certificates can be reloaded via:
sudo kill -SIGUSR1 $(cat /var/run/tomcat.pid)
This signals the native component to reload certificates.
For critical systems, implement:
- Two-phase keystore update (write to temp file then atomic rename)
- Health checks after reload
- Fallback to previous certificate on failure
Many production environments require periodic SSL certificate rotation for security compliance, but restarting Tomcat servers causes unwanted downtime. The standard JSSE implementation in Tomcat loads certificates only during initialization, creating this operational challenge.
While Tomcat doesn't natively support certificate hot-reloading, these configuration tweaks can help:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig certificateVerification="false"
truststoreFile="conf/keystore.jks"
truststorePassword="changeit"
reloadSslHostConfig="true">
<Certificate certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
The reloadSslHostConfig
attribute enables some level of dynamic reloading, but full certificate rotation still requires connector restart.
For true zero-downtime certificate rotation, consider these approaches:
1. JMX-Based Reload
import javax.management.*;
import java.lang.management.*;
ManagementFactory.getPlatformMBeanServer().invoke(
new ObjectName("Catalina:type=ProtocolHandler,port=8443"),
"reloadSslHostConfigs",
new Object[]{},
new String[]{}
);
2. Custom Connector Implementation
Extend org.apache.tomcat.util.net.AbstractEndpoint
:
public class HotReloadSSLContext extends SSLUtil {
@Override
public SSLContext createSSLContext() throws Exception {
// Implement your keystore monitoring logic here
if (certificateModified()) {
return super.createSSLContext(); // Reinitializes with new certs
}
return getCachedContext();
}
}
For mission-critical systems, consider:
- Fronting Tomcat with Nginx (cert reload via
nginx -s reload
) - Using Kubernetes ingress controllers with automatic cert rotation
- Implementing a certificate manager like HashiCorp Vault
When implementing any solution:
- Monitor performance impact of frequent reloads
- Implement proper file locking for keystore updates
- Consider certificate chain validity during rotation
- Test thoroughly with your specific TLS cipher suites
Here's a production-tested approach combining file monitoring with JMX:
public class CertWatcher implements Runnable {
private final String keystorePath;
private long lastModified;
public CertWatcher(String path) {
this.keystorePath = path;
this.lastModified = new File(path).lastModified();
}
@Override
public void run() {
while (true) {
long current = new File(keystorePath).lastModified();
if (current > lastModified) {
reloadCertificates();
lastModified = current;
}
Thread.sleep(5000);
}
}
private void reloadCertificates() {
try {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
mbs.invoke(new ObjectName("Catalina:type=ProtocolHandler,port=8443"),
"reloadSslHostConfigs", null, null);
} catch (Exception e) {
// Handle proper logging
}
}
}