Skip to content

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 (or tomcat10). The config file is at /etc/tomcat9/server.xml rather 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.


Related Guides

View all Web Servers & Proxies guides →

Configured TLS? Now Monitor It.

Generator Labs alerts you before certificates expire, get revoked, or fail chain validation, across HTTPS, SMTPS, IMAPS, LDAPS, and more.

Certificate Monitoring →