Apache Tomcat: supported versions, install, and use with httpd
Apache Tomcat runs Java web applications: it implements the Jakarta Servlet, Pages (JSP), Expression Language and WebSocket specifications and serves them over HTTP. As of November 2026 three branches are supported: 11.0 (latest 11.0.27), 10.1 (10.1.61) and 9.0 (9.0.123), and Tomcat 9.0 support ends on 31 March 2027.
What Tomcat is
Tomcat is a servlet container. A Java developer writes a web application as servlets, JSP pages and supporting classes, packs it into a WAR file (a zip archive with a fixed layout), and drops it into Tomcat. Tomcat accepts the HTTP request, picks the right application and servlet, runs it, and sends back the response.
It is not a full Jakarta EE application server. It covers the web-tier specifications listed above plus Jakarta Authentication and Annotations, but not, for example, Enterprise Beans or messaging. Many frameworks only need the web tier, which is why Tomcat is so common: Spring applications, for example, are often deployed as WAR files on Tomcat or run with Tomcat embedded inside the application.
Architecture in plain words
- Connectors listen on a port and speak a protocol. The default
server.xmldefines an HTTP/1.1 connector on port 8080. An optional AJP connector (port 8009) speaks the binary AJP protocol used by web-server front ends. - Engine, Host, Context. The engine processes requests for a service; each Host is a virtual host with an application folder (
webappsby default); each Context is one web application. - Catalina is the servlet container itself, and Jasper compiles JSP pages into servlets.
- Valves are filters at container level, for example the access log valve or the Remote IP valve described below.
A Tomcat installation has two roots. CATALINA_HOME holds the binary distribution; CATALINA_BASE holds one instance's conf, logs, webapps, work and temp folders. Keeping them separate makes upgrades simple: you replace the binaries and keep your configuration.
Supported versions
The project's "Which version do I want?" page lists these supported branches (as of November 2026; all three latest releases came out on 12 October 2026):
| Branch | Latest release | Servlet spec | Java needed | Status |
|---|---|---|---|---|
| 11.0.x | 11.0.27 | 6.1 | 17 or later | Current focus of development |
| 10.1.x | 10.1.61 | 6.0 | 11 or later | Supported; no end date announced |
| 9.0.x | 9.0.123 | 4.0 | 8 or later | Support ends 31 March 2027 |
Everything older is end of life: 10.0.x (2022-10-31), 8.5.x (2024-03-31), 8.0.x (2018-06-30) and 7.0.x (2021-03-31) among them. The project tells users of those versions to upgrade.
The end of Tomcat 9.0 and the new 9.1 branch
The end-of-support announcement for 9.0.x (published 11 February 2026) says that after 31 March 2027 there will very probably be no more 9.0.x releases and security reports will not be checked against 9.0.x. Download links and the latest release are removed from the mirrors after 30 June 2027; old releases stay in the archive.
For users who cannot leave the old javax.* APIs yet, a 9.1.x branch is due shortly before 9.0 support ends, with releases planned until 31 December 2030. The differences are small: 9.1 drops the APR/native connectors for HTTP, HTTPS and AJP, and supports only Tomcat Native 2.0.x, not 1.3.x (the project has a separate end-of-support notice for Tomcat Native 1.3.x). If you use the APR connectors, move to the NIO connectors first. The project still recommends moving to a newer branch rather than staying on 9.1.
javax vs jakarta: the big break
Tomcat 10.0 changed the package names of the specification APIs from javax.servlet to jakarta.servlet (and likewise for JSP, EL and WebSocket). An application built for Tomcat 9 must be recompiled against the new APIs, or converted. Tomcat 10.1 and 11 can convert an old application at deploy time: put the WAR in the webapps-javaee folder and the converted copy appears in webapps. The separate Tomcat Migration Tool for Jakarta EE (1.0.13, released 5 October 2026) does the same conversion ahead of time.
Install and try it
From the Apache release tarball (any Linux)
Tomcat 11 needs Java 17 or later. On Debian 13 the default Java is OpenJDK 21:
sudo apt install default-jre-headless # Debian/Ubuntu
# RHEL/Fedora: sudo dnf install java-21-openjdk-headless
java -version
Download, verify and unpack (the SHA-512 file and the release managers' KEYS file sit next to each release):
cd /tmp
curl -O https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.27/bin/apache-tomcat-11.0.27.tar.gz
curl -O https://downloads.apache.org/tomcat/tomcat-11/v11.0.27/bin/apache-tomcat-11.0.27.tar.gz.sha512
curl -O https://downloads.apache.org/tomcat/tomcat-11/v11.0.27/bin/apache-tomcat-11.0.27.tar.gz.asc
curl -O https://downloads.apache.org/tomcat/tomcat-11/KEYS
sha512sum -c apache-tomcat-11.0.27.tar.gz.sha512
gpg --import KEYS
gpg --verify apache-tomcat-11.0.27.tar.gz.asc apache-tomcat-11.0.27.tar.gz
sudo tar -xzf apache-tomcat-11.0.27.tar.gz -C /opt
Start it and check that it answers:
/opt/apache-tomcat-11.0.27/bin/startup.sh
curl -I http://localhost:8080/
/opt/apache-tomcat-11.0.27/bin/shutdown.sh
Logs go to logs/catalina.out and the dated files beside it. For a real server, run Tomcat as its own unprivileged user (never root), set memory options in CATALINA_OPTS inside bin/setenv.sh rather than JAVA_OPTS, and keep CATALINA_BASE separate from the unpacked release.
From Debian packages
Debian 13 (trixie) packages both current branches: tomcat11 (11.0.22 with Debian's security patches, as of November 2026) and tomcat10 (10.1.55).
sudo apt install tomcat11
systemctl status tomcat11
Distribution packages lag behind upstream version numbers but receive security fixes from the distribution's security team. Pick one route and stay with it; mixing a tarball and a package on one host leads to confusion about which one is running.
Tomcat behind Apache httpd
A common layout puts Apache httpd in front: it terminates HTTPS, serves static files, and forwards application requests to Tomcat on the same machine or a private network.
Option 1: mod_proxy_http (recommended default)
Plain HTTP between httpd and Tomcat is the simplest option, easy to debug with curl, and works with any back end. Enable the modules (Debian/Ubuntu; on RHEL/Fedora they are loaded by /etc/httpd/conf.modules.d/ already):
sudo a2enmod proxy proxy_http headers ssl
Inside the HTTPS virtual host (your existing SSLEngine and certificate lines stay as they are):
<VirtualHost *:443>
ServerName app.example.com
# ... SSLEngine on, SSLCertificateFile, SSLCertificateKeyFile ...
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass "/" "http://127.0.0.1:8080/"
ProxyPassReverse "/" "http://127.0.0.1:8080/"
</VirtualHost>
mod_proxy_http adds X-Forwarded-For on its own. To make Tomcat use the real client address and see that the original request was HTTPS, add the Remote IP valve inside the <Host> element of server.xml:
<Valve className="org.apache.catalina.valves.RemoteIpValve" />
By default it reads X-Forwarded-For and X-Forwarded-Proto and trusts proxies on loopback and private address ranges; set internalProxies if your proxy sits elsewhere or you want a narrower list. Finally, bind the HTTP connector to loopback so nobody can bypass httpd: add address="127.0.0.1" to the <Connector port="8080" ...> element. Test and reload httpd:
sudo apachectl configtest && sudo systemctl reload apache2 # RHEL/Fedora: httpd
On RHEL with SELinux enforcing, httpd may be refused when it connects to port 8080 ("permission denied" in error_log). Allow outbound proxy connections with sudo setsebool -P httpd_can_network_connect 1. The full proxy setup is covered in the reverse proxy guide; several Tomcats behind one httpd are covered in load balancing.
Option 2: mod_proxy_ajp
AJP is a binary protocol that passes TLS details and the authenticated user to Tomcat. It is useful mainly when an application depends on those attributes, or you are migrating from mod_jk. Tomcat treats AJP connections as more trusted than HTTP ones, so the port must never be reachable by untrusted users.
The AJP connector ships commented out in the default server.xml. Enable it on loopback with a secret:
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secret="replace-with-a-long-random-string" />
Tomcat refuses to start an AJP connector without a secret, because secretRequired defaults to true. On the httpd side (2.4.42 or later), pass the same secret:
sudo a2enmod proxy proxy_ajp
# in the virtual host:
ProxyPass "/" "ajp://127.0.0.1:8009/" secret=replace-with-a-long-random-string
The secret sits in plain text in both files, so keep them readable only by root and the service user.
Ghostcat (CVE-2020-1938)
In February 2020 the Tomcat team published CVE-2020-1938, rated Important, better known as Ghostcat. Before 9.0.31 (and 8.5.51), Tomcat shipped with the AJP connector enabled and listening on all addresses. Anyone who could reach port 8009 could read any file in a web application, including WEB-INF, and make Tomcat process any file as a JSP. If the application also accepted file uploads stored inside the application, this became remote code execution. The fix hardened the AJP defaults, which is where the secret requirement and loopback-only default come from.
Check now. If you run any Tomcat older than the supported releases above, run ss -ltnp | grep 8009. A listener on 0.0.0.0 or a public address means you should firewall it, disable the AJP connector if you do not use it, and upgrade.
Upgrades and security advisories
- Where fixes are listed. Each branch has its own page (Tomcat 11, 10 and 9 security pages on tomcat.apache.org) listing every fixed CVE with severity and the first fixed version. The 12 October 2026 releases, for example, fixed seven CVEs in 9.0.123.
- How fixes ship. The project normally does not publish binary patches for single vulnerabilities: you upgrade to the release that contains the fix.
- Announcements. Subscribe to the low-volume
announce@tomcat.apache.orglist (send a message toannounce-subscribe@tomcat.apache.org) for releases and security notices. - Reporting. Undisclosed vulnerabilities go privately to
security@tomcat.apache.org; that address does not answer configuration questions. - Upgrading within a branch (for example 11.0.26 to 11.0.27): unpack the new release next to the old one, point your service at the new
CATALINA_HOME, keep the sameCATALINA_BASE, restart, and read the changelog for changed defaults. Restarting Tomcat interrupts running requests, so plan a short window or use two instances behind a load balancer. - Libraries count too. Your applications bring their own JARs. Tomcat itself does not use Log4j, but many applications do; see the Log4j page.
Project links
- tomcat.apache.org: news, downloads and documentation for each branch.
- Which version do I want?: the supported-branch table.
- Security reports: per-branch vulnerability pages.
Sources
- Which version do I want?, Apache Tomcat
- Apache Tomcat home page (release news)
- End of support for Apache Tomcat 9.0.x, Apache Tomcat
- Tomcat 11 downloads, Apache Tomcat
- Running Tomcat (RUNNING.txt), Tomcat 11.0 documentation
- Migration guide to Tomcat 10, Apache Tomcat
- Tomcat Migration Tool for Jakarta EE downloads, Apache Tomcat
- The AJP Connector, Tomcat 11.0 configuration reference
- The Valve Component (Remote IP Valve), Tomcat 11.0 configuration reference
- Proxy Support How-To, Tomcat 11.0 documentation
- Default conf/server.xml, Apache Tomcat source (11.0.x branch)
- Security reports, Apache Tomcat
- Apache Tomcat 9.x vulnerabilities (CVE-2020-1938), Apache Tomcat
- Mailing lists, Apache Tomcat
- mod_proxy_ajp, Apache HTTP Server 2.4 documentation
- Tomcat packages in Debian stable, packages.debian.org