Apache Tomcat is an open-source Java servlet container — the classic way to run Java web applications packaged as WAR files. (Spring Boot apps with an embedded server don’t need it; see deploying a Spring Boot JAR.)
Which version?
- Tomcat 10.1 — Jakarta EE 10 (
jakarta.*packages), Java 11+. - Tomcat 11 — Jakarta EE 11, Java 17+.
- Tomcat 9 — older Java EE (
javax.*packages), for legacy apps.
Applications built for javax.servlet won’t run on Tomcat 10+ without migration — check what your app expects.
1. Install Java
sudo apt update
sudo apt install -y openjdk-21-jre-headless
See installing Java.
2. Create a user and download Tomcat
Ubuntu packages Tomcat in some releases, but the official binary distribution gives you the current version and a standard layout:
sudo useradd --system --home-dir /opt/tomcat --shell /usr/sbin/nologin tomcat
TOMCAT_VERSION=10.1.34 # check tomcat.apache.org for the latest
cd /tmp
wget https://dlcdn.apache.org/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz
wget https://downloads.apache.org/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz.sha512
sha512sum -c apache-tomcat-${TOMCAT_VERSION}.tar.gz.sha512
sudo mkdir -p /opt/tomcat
sudo tar xzf apache-tomcat-${TOMCAT_VERSION}.tar.gz -C /opt/tomcat --strip-components=1
sudo chown -R tomcat:tomcat /opt/tomcat
sudo chmod -R u+x /opt/tomcat/bin
(Older releases move from dlcdn to archive.apache.org.)
3. systemd service
/etc/systemd/system/tomcat.service:
[Unit]
Description=Apache Tomcat
After=network.target
[Service]
Type=forking
User=tomcat
Group=tomcat
Environment=JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment="CATALINA_OPTS=-Xms512m -Xmx1024m -server -XX:+UseG1GC"
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
SuccessExitStatus=143
Restart=on-failure
[Install]
WantedBy=multi-user.target
Check JAVA_HOME with readlink -f $(which java) (strip /bin/java).
sudo systemctl daemon-reload
sudo systemctl enable --now tomcat
curl -I http://127.0.0.1:8080
4. Listen on localhost only
In /opt/tomcat/conf/server.xml, bind the HTTP connector to localhost (Nginx will be the public entry point):
<Connector port="8080" protocol="HTTP/1.1" address="127.0.0.1"
connectionTimeout="20000" redirectPort="8443" />
Keep the shutdown port (8005) bound to localhost (default) — or disable it with port="-1" if you only stop Tomcat via systemd.
5. Manager app: lock it down
The Manager web app deploys and undeploys applications — powerful, and a frequent attack target. If you use it, define a user in conf/tomcat-users.xml:
<role rolename="manager-gui"/>
<user username="admin" password="a-long-random-password" roles="manager-gui"/>
By default, webapps/manager/META-INF/context.xml allows access only from localhost — keep it that way and reach it through an SSH tunnel (ssh -L 8080:127.0.0.1:8080 user@server). If you don’t need it, delete webapps/manager, webapps/host-manager, webapps/docs and webapps/examples.
Restart after changes: sudo systemctl restart tomcat.
6. Deploy a WAR
Copy the WAR into webapps/; Tomcat unpacks and deploys it automatically:
sudo cp myapp.war /opt/tomcat/webapps/
sudo chown tomcat:tomcat /opt/tomcat/webapps/myapp.war
It’s served at /myapp/. To serve it at the root, name it ROOT.war (after removing the default ROOT app).
7. Nginx in front with HTTPS
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo certbot --nginx -d app.example.com
Tell Tomcat about the proxy so request.isSecure() and redirects are correct — add the RemoteIpValve to the <Host> in server.xml:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" />
8. Logs and maintenance
Logs are in /opt/tomcat/logs/ (catalina.out, access logs). Rotate catalina.out with logrotate (copytruncate) — see logrotate. Upgrade by extracting a new version into a fresh directory, copying conf/ customisations and webapps/, and switching the service paths.
Related: Nginx reverse proxy and installing Java.