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.

  • Tomcat
  • Java
  • Ubuntu