An HTTPS connector on 8443 that still negotiates TLSv1.0 or TLSv1.1 is active downgrade surface. Clients that can force TLSv1.0 can exploit protocol-level weaknesses, and ciphers that exist only to support legacy protocols weaken posture for every client. The fix has two parts: restrict the protocol list to TLSv1.2 and TLSv1.3, and prune the cipher list so weak suites are not offered.
This is a configuration change, not a runtime incident, but it has runtime consequences. A misconfigured SSLHostConfig prevents the connector from starting. A Tomcat upgrade can silently re-enable TLSv1.3 ciphers you intended to exclude. The procedure covers the version split between Tomcat 8.5/9 (where sslEnabledProtocols is deprecated but functional) and Tomcat 10/11 (where it is removed), the cipher attribute split in 9.0.115/10.1.52/11.0.18, and external verification.
Prerequisites
- Tomcat 8.5 or newer. Tomcat 7.x and below use a different SSL model and are long past end of life.
- Write access to
$CATALINA_BASE/conf/server.xmland a way to restart Tomcat. opensslandnmapon a host that can reach port 8443. Verification must run from outside the Tomcat process; a correct config file is not proof.- Your Tomcat major version. Attribute names differ between 8.5/9 and 10/11; wrong syntax causes startup failure.
- Your JDK version. TLSv1.0 and TLSv1.1 are disabled by default in Java 8u292 and later via
jdk.tls.disabledAlgorithmsin$JAVA_HOME/conf/security/java.security, so a modern JDK may already refuse these protocols even if Tomcat requests them. ChaCha20-Poly1305 suites may require a newer JDK; verify before including them.
Procedure
1. Identify the Tomcat version and connector type
$CATALINA_HOME/bin/version.sh
The version determines which syntax you must use. On Tomcat 10.1 and later, the APR/Native connector (Http11AprProtocol) is reported as removed; use Http11NioProtocol. If you previously relied on APR for TLS performance, switch to NIO with the OpenSSL implementation via sslImplementationName="org.apache.tomcat.util.net.openssl.OpenSSLImplementation" on the SSLHostConfig.
2. Locate the 8443 connector
grep -A 15 'port="8443"' $CATALINA_BASE/conf/server.xml
Note any existing sslEnabledProtocols, ciphers, sslProtocol, keystoreFile, or keystorePass attributes on the <Connector> element. On Tomcat 8.5/9 these are deprecated aliases for attributes on an auto-created SSLHostConfig with hostname _default_. On Tomcat 10/11 they are removed and cause a startup error like “failed to set property [sslEnabledProtocols]”.
3. Configure protocols
The configuration splits by major version.
flowchart td
A[Identify Tomcat major version] --> B{8.5 or 9.x?}
B -- yes --> C[sslEnabledProtocols works but deprecated]
B -- no --> D{10.x or 11.x?}
D -- yes --> E[sslEnabledProtocols removed]
C --> F[Use SSLHostConfig protocols attr]
E --> F
F --> G[Set protocols to TLSv1.2,TLSv1.3]
G --> H[Verify with openssl s_client]For Tomcat 8.5 and 9.x, the deprecated sslEnabledProtocols attribute on the Connector still works, but the supported path is a nested SSLHostConfig. For Tomcat 10.x and 11.x, SSLHostConfig is mandatory.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig
protocols="TLSv1.2,TLSv1.3"
ciphers="HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!kRSA"
cipherSuites="TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256">
<Certificate certificateKeystoreFile="conf/keystore.p12"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
Key points:
protocols="TLSv1.2,TLSv1.3"restricts the protocol list to an explicit set. If you omitprotocols, the default isall, which expands to include TLSv1.0 and TLSv1.1. Omitting the attribute is how most weak-protocol exposures happen. Theprotocolsattribute also accepts+/-prefix modifiers against the default set (for example,all,-TLSv1,-TLSv1.1), but an explicit list is clearer for auditing.sslProtocolis notprotocols. SettingsslProtocol="TLSv1.2"does not restrict the allowed list to TLSv1.2. UseprotocolsonSSLHostConfigto control which versions are negotiated.- Remove all deprecated Connector-level SSL attributes (
keystoreFile,keystorePass,ciphers,sslProtocol,sslEnabledProtocols) when you add an explicitSSLHostConfig. Mixing them causes Tomcat to auto-create a secondSSLHostConfigfor_default_, and startup fails with “Multiple SSLHostConfig elements were provided for the host name [default]. Hostnames must be unique.”
4. Configure ciphers
The cipher attribute split in Tomcat 9.0.115, 10.1.52, and 11.0.18 is the most common silent regression. Before those versions, a single ciphers attribute held both TLSv1.2 and TLSv1.3 cipher names. After, ciphers is for TLSv1.2 and below, and cipherSuites is for TLSv1.3.
If you place TLSv1.3 cipher names (anything starting with TLS_AES_ or TLS_CHACHA20_) in the ciphers attribute on a split version, Tomcat logs a warning and ignores them. The connector then offers all default TLSv1.3 ciphers, including any you intended to exclude. The warning looks like: “The TLS 1.3 cipher suite [TLS_AES_256_GCM_SHA384] included in the TLS 1.2 and below ciphers list will be ignored”.
Check your version and use both attributes on split versions. On earlier 9.0.x or 10.1.x, place all cipher names in ciphers.
5. Apply the change
Tomcat does not hot-reload SSL configuration. A restart is required.
# Restart Tomcat (adjust for your init system)
sudo systemctl restart tomcat
Watch the startup log for SSL errors. A failed SSLHostConfig prevents the connector from binding to 8443, so the JVM stays alive but the HTTPS port does not listen. A process-alive check is not sufficient.
Verifying it works
Verification must be external. The config file is not the source of truth for what the connector offers.
# Verify TLSv1.0 is refused (should fail or show no protocol)
openssl s_client -connect localhost:8443 -tls1 </dev/null 2>&1 | grep -i "protocol\|error"
# Verify TLSv1.1 is refused
openssl s_client -connect localhost:8443 -tls1_1 </dev/null 2>&1 | grep -i "protocol\|error"
# Verify TLSv1.2 works
openssl s_client -connect localhost:8443 -tls1_2 </dev/null 2>&1 | grep -i "protocol"
# Verify TLSv1.3 works
openssl s_client -connect localhost:8443 -tls1_3 </dev/null 2>&1 | grep -i "protocol"
# Enumerate all offered ciphers and grades
nmap --script ssl-enum-ciphers -p 8443 localhost
Expected results:
-tls1and-tls1_1should fail with a handshake or protocol error. If either connects and reportsProtocol : TLSv1orTLSv1.1, the restriction did not take effect. Note: on OpenSSL 3.x, these flags may not be available if TLS 1.0 support was compiled out on the client side. Use an older OpenSSL or a tool liketestssl.shif you need to confirm from a legacy client perspective.-tls1_2and-tls1_3should connect successfully.nmap ssl-enum-ciphersshould list only strong ciphers with no TLSv1.0 or TLSv1.1 section.
Run these from a host outside the Tomcat server. A localhost check confirms the connector config; an external check confirms firewalls, load balancers, and TLS-terminating proxies are not re-enabling weak protocols.
Common pitfalls
sslProtocolis notsslEnabledProtocols.sslProtocolcontrols the protocol version negotiated, not the allowed list. SettingsslProtocol="TLSv1.2"does not disable TLSv1.0 and TLSv1.1. UseprotocolsonSSLHostConfig.- Cipher downgrade on upgrade. Moving to Tomcat 9.0.115+, 10.1.52+, or 11.0.18+ with TLSv1.3 cipher names still in
cipherssilently re-enables all default TLSv1.3 ciphers. Check the log for the “will be ignored” warning after every upgrade. - Multiple SSLHostConfig error. Mixing deprecated Connector-level SSL attributes with an explicit
SSLHostConfigproduces “Multiple SSLHostConfig elements were provided for the host name [default]”. Remove all deprecated attributes from the Connector. - ChaCha20 on Java 11. The
TLS_CHACHA20_POLY1305_SHA256suite may require Java 12 or later. On Java 11, omit it fromcipherSuitesor the connector may fail to start. - JDK already disables TLSv1.0/1.1. Java 8u292+ disables TLSv1.0 and TLSv1.1 via
jdk.tls.disabledAlgorithms. A scanner may still report them if the JDK config was modified. Verify the JDK config, not just Tomcat.
Signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
| 8443 port listening | Connector failed to start after config change | ss -tnl sport = :8443 shows no listener |
| TLS handshake success rate | Misconfigured ciphers cause handshake failures | Spike in connection resets or client-side TLS errors |
| Certificate expiry | Silent total outage independent of protocol/cipher config | Days to expiry approaching zero; needs external check |
| Startup log for SSL warnings | Cipher downgrade bug is silent except for a log line | “will be ignored” warning after upgrade |
How Netdata helps
- Port and service checks. TCP and HTTP checks confirm 8443 is listening and completing a TLS handshake after a config change, catching the case where the JVM is alive but the connector failed to start.
- Process-alive correlation. Pairing the port check with the JVM process-alive signal distinguishes “Tomcat is down” from “Tomcat is up but the HTTPS connector did not bind”.
- External certificate expiry monitoring. Certificate checks probe the chain from outside the host, which is the only reliable way to catch expiry before it becomes a total outage.
- Error rate correlation. A spike in 5xx errors or connection resets immediately after a TLS config change points back to the cipher or protocol restriction.
- Startup log monitoring. The “will be ignored” cipher warning in
catalina.outis the only in-process signal for the silent cipher downgrade bug.
Related guides
- Tomcat 5xx error rate: separating server failures from crawler 404s
- Tomcat accept queue overflow: acceptCount, somaxconn, and Recv-Q
- Tomcat access log setup: adding %D and %T for per-request latency
- Tomcat java.net.BindException: Address already in use: the connector never starts
- Tomcat average latency lies: why you need p95/p99 from the access log
- Tomcat threads blocked forever: the missing outbound timeout
- Tomcat classloader leak on redeploy: why the old WebappClassLoader never dies
- Tomcat connection refused: maxConnections and acceptCount both exhausted
- Tomcat accepts connections but never responds: the TCP-connect trap
- Tomcat file descriptor usage: OpenFileDescriptorCount vs the ulimit
- Tomcat frequent Full GC: pause time, G1, and the 5% overhead rule
- Tomcat GC death spiral: full GCs dominating and throughput collapsing






