Skip to main content

Restarting Apache Tomcat on Linux — Stop, Start, and Troubleshooting

5 min read Updated May 31, 2026
Share:
On this page (17sections)

Use this guide when you need a clean Tomcat restart on a Linux server — after a deployment, config change, or when the instance is hung. It covers the approaches used today: systemd (preferred on most servers), catalina scripts, and safe process cleanup when graceful shutdown fails.

Version note: Examples assume Apache Tomcat 10.1 or 11 on Linux. Tomcat 10+ uses Jakarta EE (jakarta.* packages). Tomcat 11 requires Java 17+; Tomcat 10.1 requires Java 11+. Adjust paths if your install uses a different layout.

Before you restart

  1. Notify users if this is production — brief downtime or failed sessions may occur.
  2. Note CATALINA_HOME — usually /opt/tomcat, /usr/share/tomcat10, or a custom path like /home/app/apache-tomcat-10.1.x.
  3. Confirm the run user — Tomcat should run as a dedicated non-root user (e.g. tomcat), not root.
  4. Back up conf/server.xml, deployed WARs, and any custom context configs if you changed them recently.

Set environment variables if your install expects them:

export CATALINA_HOME=/opt/tomcat
export CATALINA_BASE=/opt/tomcat   # often same as CATALINA_HOME
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

Most Linux packages register Tomcat as a systemd service.

# Check service name (varies by distro)
systemctl list-units --type=service | grep -i tomcat

# Graceful restart
sudo systemctl restart tomcat
# or: tomcat10, tomcat11, tomcat.service

# Stop and start separately
sudo systemctl stop tomcat
sudo systemctl start tomcat

# Status and recent logs
sudo systemctl status tomcat
sudo journalctl -u tomcat -n 100 --no-pager

Enable on boot (if not already):

sudo systemctl enable tomcat

This is the cleanest approach: systemd sends the correct stop signal, tracks PID, and logs to the journal.


Method 2 — catalina.sh scripts

When Tomcat is installed manually (tarball), use the scripts in $CATALINA_HOME/bin:

cd "$CATALINA_HOME/bin"

# Graceful stop (preferred)
./catalina.sh stop

# Wait a few seconds, then start
./catalina.sh start

# Foreground run (debugging only — use a separate terminal)
./catalina.sh run

Legacy wrappers still work on many installs:

./shutdown.sh    # calls catalina stop
./startup.sh     # calls catalina start (detached)

Do not run startup.sh as root in production. Use the tomcat service user:

sudo -u tomcat "$CATALINA_HOME/bin/catalina.sh" start

Method 3 — When Tomcat will not stop

If systemctl stop or catalina.sh stop hangs, find and terminate the process carefully.

1. Find the Tomcat process

Prefer matching catalina over a broad java grep:

ps aux | grep '[c]atalina'
# or
pgrep -af catalina

Example output:

tomcat  12845  ... org.apache.catalina.startup.Bootstrap start

The second column is the PID (here 12845).

2. Try graceful kill first

kill -15 12845          # SIGTERM — allows shutdown hooks
sleep 10
ps -p 12845 || echo "Process stopped"

3. Force kill only if needed

kill -9 12845           # SIGKILL — last resort; may leave lock files

Or kill all Tomcat JVMs matching catalina:

pkill -15 -f 'org.apache.catalina.startup.Bootstrap'
sleep 10
pkill -9 -f 'org.apache.catalina.startup.Bootstrap'   # only if still running

4. Clean up and start again

After a forced kill, remove stale PID or lock files if present:

rm -f "$CATALINA_HOME/work/Catalina/localhost/*/SESSIONS.ser" 2>/dev/null
# Check logs before restart
tail -50 "$CATALINA_HOME/logs/catalina.out"

Then start via systemd or catalina.sh start.


Verify Tomcat is running

Check logs

cd "$CATALINA_HOME/logs"
tail -f catalina.out

Look for:

  • Server startup in [XXXX] milliseconds
  • No repeating SEVERE or OutOfMemoryError lines
  • Each web application context started (your WAR or ROOT context)

Check the HTTP port

Default port is 8080 (configured in conf/server.xml):

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/
ss -tlnp | grep 8080

A response code 200, 302, or 404 from the root context usually means the connector is up.


File permissions (modern practice)

Tomcat needs read access to its install directory and write access to logs/, work/, and temp/. Use a dedicated user and avoid chmod 777.

# Tomcat install owned by service user
sudo chown -R tomcat:tomcat "$CATALINA_HOME"

# Directories: owner rwx, group rx
sudo find "$CATALINA_HOME" -type d -exec chmod 750 {} \;

# Files: owner rw, group r
sudo find "$CATALINA_HOME" -type f -exec chmod 640 {} \;

# Writable runtime dirs
sudo chmod 770 "$CATALINA_HOME/logs" "$CATALINA_HOME/work" "$CATALINA_HOME/temp"

If your app writes uploads outside Tomcat (e.g. /var/app/uploads):

sudo chown tomcat:tomcat /var/app/uploads
sudo chmod 750 /var/app/uploads

Grant only what the process needs — world-writable directories are a security risk.


Common restart scenarios

ScenarioWhat to do
Deploy new WARStop Tomcat → replace WAR in webapps/ → clear exploded folder if needed → start
Change server.xmlFull restart required (systemctl restart tomcat)
Out of memoryFix -Xmx in setenv.sh or systemd override, then restart
Port 8080 in usess -tlnp | grep 8080 — stop conflicting process or change connector port
Stuck after kill -9Remove work/ cache for the app, check catalina.out for lock errors

setenv.sh example (heap size)

Create $CATALINA_HOME/bin/setenv.sh:

#!/bin/sh
export CATALINA_OPTS="-Xms512m -Xmx1024m -Dfile.encoding=UTF-8"
chmod +x "$CATALINA_HOME/bin/setenv.sh"
sudo chown tomcat:tomcat "$CATALINA_HOME/bin/setenv.sh"

Spring Boot with embedded Tomcat

If you run a Spring Boot executable JAR (embedded Tomcat), you do not use catalina.sh. Restart the application process instead:

# systemd example
sudo systemctl restart myapp

# manual JAR
kill -15 "$(pgrep -f myapp.jar)"
java -jar myapp.jar &

For dev, Spring Boot DevTools supports automatic restart on classpath changes — that is separate from standalone Tomcat administration.


Quick checklist

  • Stop via systemd or catalina.sh stop before force-killing
  • Confirm process exit with ps or systemctl status
  • Read catalina.out after start — no fatal errors
  • Hit the app on its HTTP port or through your reverse proxy
  • Permissions: tomcat user, no 777 on app or upload dirs

References

Related Tutorials

Search tutorials