Last updated: 2026-06-25
Tomcat TLS/SSL Configuration Guide
This guide provides recommended TLS/SSL settings for Apache Tomcat. Tomcat supports TLS through two implementations: the default Java JSSE connector and the OpenSSL-based connector (via Tomcat Native/APR). This guide covers both approaches.
Prerequisites
- Tomcat 9.0.31 or later, or Tomcat 10+ (for TLS 1.3 support)
- Java 11 or later (for TLS 1.3 support in JSSE mode)
- For OpenSSL mode: Tomcat Native 1.2.23+ and OpenSSL 1.1.1+
- A valid SSL/TLS certificate
Certificate Formats
Tomcat supports different certificate formats depending on the connector type:
- JSSE (Java) - Uses Java keystore (JKS/PKCS12) or PEM files (Tomcat 9.0.13+)
- OpenSSL/APR - Uses PEM files
To create a PKCS12 keystore from PEM files:
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out keystore.p12 -name tomcat
JSSE Connector (Default)
Configure TLS in the <Connector> element within server.xml ($CATALINA_HOME/conf/server.xml). The JSSE connector uses Java cipher suite names.
Protocol Versions
Restrict to TLS 1.2 and TLS 1.3:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig protocols="TLSv1.2+TLSv1.3">
<!-- certificate and cipher configuration here -->
</SSLHostConfig>
</Connector>
Cipher Suites (Java Names)
Use only strong AEAD cipher suites with ECDHE key exchange. Java uses its own cipher naming convention:
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
ciphers="TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
honorCipherOrder="false">
Note: All ChaCha20-Poly1305 ciphers (TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) require Java 12+. On Java 11, omit all three and use only the AES-GCM ciphers.
Certificate Configuration (Keystore)
Using a PKCS12 keystore:
<SSLHostConfig>
<Certificate certificateKeystoreFile="/etc/tomcat/ssl/keystore.p12"
certificateKeystorePassword="changeit"
certificateKeystoreType="PKCS12" />
</SSLHostConfig>
Certificate Configuration (PEM Files)
Tomcat 9.0.13+ supports PEM files directly with the JSSE connector:
<SSLHostConfig>
<Certificate certificateFile="/etc/tomcat/ssl/cert.pem"
certificateKeyFile="/etc/tomcat/ssl/privkey.pem"
certificateChainFile="/etc/tomcat/ssl/chain.pem" />
</SSLHostConfig>
OpenSSL Connector (APR/Tomcat Native)
If Tomcat Native is installed, you can use the OpenSSL implementation for potentially better performance. This uses OpenSSL cipher names (same as Nginx/Apache).
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
ciphers="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"
honorCipherOrder="false">
<Certificate certificateFile="/etc/tomcat/ssl/cert.pem"
certificateKeyFile="/etc/tomcat/ssl/privkey.pem"
certificateChainFile="/etc/tomcat/ssl/chain.pem" />
</SSLHostConfig>
</Connector>
Note: Http11AprProtocol was removed in Tomcat 10.1+ (Debian 12, Ubuntu 24.04). On Tomcat 10.1+, use Http11NioProtocol with sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation" instead.
OCSP Stapling
Tomcat does not enable OCSP stapling by default. To enable it (Java 8u202+ or Java 11+), add these JVM flags to your startup options:
-Djdk.tls.server.enableStatusRequestExtension=true
-Dcom.sun.net.ssl.checkRevocation=true
HSTS and HTTPS Redirect
Tomcat does not add HSTS headers automatically. Configure the HttpHeaderSecurity filter in web.xml:
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<init-param>
<param-name>hstsEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsMaxAgeSeconds</param-name>
<param-value>63072000</param-value>
</init-param>
<init-param>
<param-name>hstsIncludeSubDomains</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
To redirect HTTP to HTTPS, add to web.xml:
<security-constraint>
<web-resource-collection>
<web-resource-name>Secure</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
Complete Configuration Example (JSSE with PEM)
<!-- On Debian/Ubuntu, config is /etc/tomcat9/server.xml (or tomcat10); use systemctl restart tomcat9 -->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<!-- Note: ChaCha20 ciphers (CHACHA20_POLY1305) require Java 12+; on Java 11, omit them -->
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
ciphers="TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
honorCipherOrder="false">
<Certificate certificateFile="/etc/tomcat/ssl/cert.pem"
certificateKeyFile="/etc/tomcat/ssl/privkey.pem"
certificateChainFile="/etc/tomcat/ssl/chain.pem" />
</SSLHostConfig>
</Connector>
Mutual TLS (mTLS)
Standard TLS authenticates only the server. Mutual TLS adds client authentication, requiring the connecting client to also present a certificate. This is an optional hardening step, not required for standard deployments. It is most useful for internal services and APIs where you control all connecting clients.
Add certificateVerification="required" to the <SSLHostConfig> element, along with a truststore containing the CA certificate that signed the client certificates:
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
certificateVerification="required"
truststoreFile="/etc/tomcat/ssl/client-ca.p12"
truststorePassword="changeit"
truststoreType="PKCS12">
<Certificate certificateFile="/etc/tomcat/ssl/cert.pem"
certificateKeyFile="/etc/tomcat/ssl/privkey.pem"
certificateChainFile="/etc/tomcat/ssl/chain.pem" />
</SSLHostConfig>
To use a PEM file as the truststore (Tomcat 9.0.51+):
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
certificateVerification="required"
truststoreFile="/etc/tomcat/ssl/client-ca.pem"
truststoreType="PEM">
<Certificate certificateFile="/etc/tomcat/ssl/cert.pem"
certificateKeyFile="/etc/tomcat/ssl/privkey.pem"
certificateChainFile="/etc/tomcat/ssl/chain.pem" />
</SSLHostConfig>
- certificateVerification="required" - Require and verify a client certificate. Connections without one are rejected.
- certificateVerification="optional" - Request a client certificate but allow connections without one.
- truststoreFile - File containing the CA certificate(s) used to verify client certificates.
The client certificate is available to web applications via request.getAttribute("jakarta.servlet.request.X509Certificate") (Tomcat 10+) or request.getAttribute("javax.servlet.request.X509Certificate") (Tomcat 9).
See RFC 8446 ยง4.3.2 for the TLS Certificate Request specification, and Wikipedia: Mutual authentication for a general overview.
Security Notes
Tomcat uses Java's JSSE (Java Secure Socket Extension) for TLS. Vulnerability fixes are tied to the JDK version in use:
- POODLE (CVE-2014-3566, 2014): SSL 3.0 disabled by default since Java 8u31 (January 2015). The recommended configuration explicitly excludes it.
- BEAST (CVE-2011-3389, 2011): TLS 1.0 disabled by default since Java 8u292 / Java 11.0.11 (April 2021); excluded from the recommended configuration.
- FREAK (CVE-2015-0204, 2015): EXPORT ciphers disabled by default since Java 8u40 (March 2015).
- Sweet32 (CVE-2016-2183, 2016): 3DES disabled by default since Java 8u151 (October 2017); excluded from the recommended cipher list.
- ROBOT (2017): Static RSA key exchange is excluded from the recommended configuration.
- Downgrade attacks: TLS_FALLBACK_SCSV supported since Java 8u31.
- LOGJAM (CVE-2015-4000, 2015): DHE with weak keys excluded; only ECDHE is recommended.
The following are not addressable through TLS configuration alone:
- Heartbleed (CVE-2014-0160, 2014): Not applicable. Java's JSSE is an independent TLS implementation not based on OpenSSL and was never affected by Heartbleed.
- BREACH (CVE-2013-3587, 2013): Exploits HTTP-level response compression (gzip/deflate on responses). Mitigated at the application layer by disabling HTTP compression or using BREACH countermeasures; TLS configuration cannot prevent it.
- DROWN (CVE-2016-0800, 2016): Not applicable. Java's JSSE does not support SSLv2.
Verification
Restart Tomcat after making changes:
$CATALINA_HOME/bin/shutdown.sh
$CATALINA_HOME/bin/startup.sh
Path note: On Debian/Ubuntu, Tomcat is managed as a system service; use
systemctl restart tomcat9(ortomcat10). The config file is at/etc/tomcat9/server.xmlrather than$CATALINA_HOME/conf/server.xml.
Test the TLS connection:
openssl s_client -connect localhost:8443 -tls1_2
openssl s_client -connect localhost:8443 -tls1_3
Check which cipher suites are available from the Java runtime:
$JAVA_HOME/bin/jrunscript -e "java.util.Arrays.asList(javax.net.ssl.SSLContext.getDefault().createSSLEngine().getSupportedCipherSuites()).stream().forEach(println)"
Test your configuration externally with the Mr.DNS SSL/TLS Certificate Check.