What is Apache Tomcat?
Apache Tomcat is the world's most widely used Java servlet container and web server. It's an open-source implementation of the Jakarta Servlet, Jakarta Server Pages (JSP), and Jakarta WebSocket specifications, developed under the Apache Software Foundation.
When people say they're "deploying to Tomcat," they mean they're using Tomcat as the runtime environment for their Java web applications. It's the "home" where your web app lives and runs.
Why Tomcat is So Popular
- Free and Open Source: Apache License 2.0, no cost, widely trusted
- Reference Implementation: The standard by which other servlet containers are measured
- Lightweight: Starts quickly, uses minimal resources compared to full application servers
- Well Documented: Extensive documentation, huge community, countless tutorials
- Production Proven: Powers millions of applications worldwide
- Spring Boot Default: The default embedded server for Spring Boot applications
- Easy to Learn: Simple directory structure and configuration
Quick Facts about Tomcat:
- Created: 1999, originally by Sun Microsystems, donated to Apache
- Current Version: Tomcat 10.1.x (Jakarta EE 10), Tomcat 11 (Jakarta EE 11)
- Written In: Java (so it runs on any platform with JVM)
- Default Port: 8080 (HTTP), 8443 (HTTPS), 8005 (shutdown)
- Implements: Servlet 6.0, JSP 3.1, EL 5.0, WebSocket 2.1
Tomcat Version History (What You Need to Know)
| Tomcat Version | Java Version | Servlet Spec | Package Names |
|---|---|---|---|
| Tomcat 8.5 | Java 7+ | Servlet 3.1 | javax.servlet.* |
| Tomcat 9 | Java 8+ | Servlet 4.0 | javax.servlet.* |
| Tomcat 10 | Java 11+ | Servlet 5.0/6.0 | jakarta.servlet.* |
| Tomcat 11 | Java 17+ | Servlet 6.1 | jakarta.servlet.* |
Tomcat 10+ uses jakarta.servlet.* package names instead of javax.servlet.*. This is due to Oracle transferring Java EE to the Eclipse Foundation. If your app uses javax.servlet, you need Tomcat 9 or earlier, OR you need to migrate your imports to jakarta.servlet.
Tomcat Directory Structure
Understanding Tomcat's directory layout is essential for configuration and troubleshooting. Here's what each folder contains:
apache-tomcat-10.1.x/
├── bin/ ← Startup/shutdown scripts
│ ├── startup.sh (Linux/Mac start)
│ ├── startup.bat (Windows start)
│ ├── shutdown.sh (Linux/Mac stop)
│ ├── shutdown.bat (Windows stop)
│ ├── catalina.sh (Main script with more options)
│ └── setenv.sh (YOUR custom JVM options - create this!)
│
├── conf/ ← Configuration files
│ ├── server.xml (Main server configuration)
│ ├── web.xml (Default web app settings)
│ ├── context.xml (Default context settings)
│ ├── tomcat-users.xml (User accounts for manager)
│ └── logging.properties (Logging configuration)
│
├── lib/ ← Tomcat's own JAR files + shared libraries
│ ├── servlet-api.jar (Servlet API)
│ ├── jsp-api.jar (JSP API)
│ └── ... (Tomcat implementation JARs)
│
├── logs/ ← Log files (check here for errors!)
│ ├── catalina.out (Main log - all console output)
│ ├── catalina.YYYY-MM-DD.log (Daily server logs)
│ ├── localhost.YYYY-MM-DD.log (Application logs)
│ └── localhost_access.YYYY-MM-DD.log (HTTP access logs)
│
├── temp/ ← Temporary files (can be cleared)
│
├── webapps/ ← YOUR APPLICATIONS GO HERE!
│ ├── ROOT/ (Default app at http://localhost:8080/)
│ ├── manager/ (Web-based management interface)
│ ├── host-manager/ (Virtual host management)
│ ├── examples/ (Example servlets - remove in production!)
│ └── myapp.war (Your app! Auto-deploys when dropped here)
│
└── work/ ← Compiled JSPs and session data
└── Catalina/ (Generated files - can be cleared)
The Most Important Directories
- webapps/: Drop your WAR files here for automatic deployment. This is where your apps live.
- conf/: All configuration.
server.xmlis the main file you'll edit. - logs/: First place to look when something goes wrong.
catalina.outhas everything. - bin/: Start and stop Tomcat from here.
Installing and Running Tomcat
Method 1: Download and Extract
# 1. Download from https://tomcat.apache.org/
# 2. Extract the archive
# Linux/Mac:
tar -xzf apache-tomcat-10.1.18.tar.gz
cd apache-tomcat-10.1.18
# 3. Make scripts executable (Linux/Mac)
chmod +x bin/*.sh
# 4. Start Tomcat
./bin/startup.sh
# Or: ./bin/catalina.sh run (to see output in terminal)
# 5. Open browser: http://localhost:8080
# You should see the Tomcat welcome page!
# 6. Stop Tomcat
./bin/shutdown.sh
Method 2: Using Package Manager
# Ubuntu/Debian
sudo apt install tomcat10
# macOS with Homebrew
brew install tomcat
# Windows with Chocolatey
choco install tomcat
Method 3: IDE Integration (Development)
// IntelliJ IDEA:
// 1. Run → Edit Configurations
// 2. + → Tomcat Server → Local
// 3. Configure Tomcat Home directory
// 4. Add your artifact (WAR) to deploy
// Eclipse:
// 1. Window → Preferences → Server → Runtime Environments
// 2. Add → Apache Tomcat v10.1
// 3. Create new Server in Servers view
Setting JVM Options
# Create bin/setenv.sh (Linux/Mac) or bin/setenv.bat (Windows)
# This file is the RIGHT place for your custom settings
# bin/setenv.sh example:
#!/bin/bash
# Memory settings
CATALINA_OPTS="$CATALINA_OPTS -Xms512m" # Initial heap
CATALINA_OPTS="$CATALINA_OPTS -Xmx2048m" # Maximum heap
# Garbage collection (for Java 11+)
CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
# Remote debugging (development only!)
CATALINA_OPTS="$CATALINA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
# Application properties
CATALINA_OPTS="$CATALINA_OPTS -Dspring.profiles.active=production"
export CATALINA_OPTS
Key Configuration Files
server.xml - The Main Configuration
<!-- conf/server.xml - Core Tomcat configuration -->
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<!-- HTTP Connector - where requests come in -->
<Connector
port="8080" <!-- Listen on this port -->
protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200" <!-- Max concurrent requests -->
minSpareThreads="10"
redirectPort="8443" />
<!-- HTTPS Connector (uncomment and configure for SSL) -->
<!--
<Connector
port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate
certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
-->
<!-- Engine processes requests -->
<Engine name="Catalina" defaultHost="localhost">
<!-- Virtual host -->
<Host name="localhost"
appBase="webapps" <!-- Where apps are -->
unpackWARs="true" <!-- Extract WAR files -->
autoDeploy="true"> <!-- Auto-deploy new WARs -->
<!-- Access logging -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
tomcat-users.xml - User Authentication
<!-- conf/tomcat-users.xml - Users for Manager app -->
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
<!-- Roles -->
<role rolename="manager-gui"/> <!-- Access manager web UI -->
<role rolename="manager-script"/> <!-- Deploy via script/API -->
<role rolename="admin-gui"/> <!-- Host manager web UI -->
<!-- Users -->
<user username="admin"
password="secretpassword"
roles="manager-gui,manager-script,admin-gui"/>
</tomcat-users>
<!-- WARNING: Change the password in production!
Consider using a more secure authentication mechanism -->
context.xml - Default Context Settings
<!-- conf/context.xml - Default settings for all web apps -->
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Database connection pool (shared by all apps) -->
<Resource
name="jdbc/mydb"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/mydb"
username="dbuser"
password="dbpassword"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"/>
<!-- Prevent session persistence across restarts -->
<Manager pathname="" />
<!-- Watch web.xml for changes (development only) -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
Deploying Applications to Tomcat
Method 1: Drop WAR File (Simplest)
# Just copy your WAR file to webapps/
cp myapp.war /opt/tomcat/webapps/
# Tomcat automatically:
# 1. Detects the new WAR file
# 2. Extracts it to webapps/myapp/
# 3. Deploys the application
# 4. Makes it available at http://localhost:8080/myapp
# To undeploy: delete the WAR and the extracted folder
rm /opt/tomcat/webapps/myapp.war
rm -rf /opt/tomcat/webapps/myapp
Method 2: Manager Web Interface
# 1. Access: http://localhost:8080/manager/html
# 2. Login with credentials from tomcat-users.xml
# 3. Scroll to "WAR file to deploy"
# 4. Choose file and click "Deploy"
# Manager also lets you:
# - Start/Stop/Reload applications
# - Undeploy applications
# - View session statistics
# - Check server status
Method 3: Maven Plugin
<!-- pom.xml - Tomcat Maven Plugin -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>tomcat-server</server> <!-- Reference to settings.xml -->
<path>/myapp</path>
</configuration>
</plugin>
<!-- In ~/.m2/settings.xml -->
<servers>
<server>
<id>tomcat-server</id>
<username>admin</username>
<password>secretpassword</password>
</server>
</servers>
# Deploy command:
mvn tomcat7:deploy # First deployment
mvn tomcat7:redeploy # Update existing
mvn tomcat7:undeploy # Remove
Understanding Context Paths
// The WAR filename determines the context path (URL)
myapp.war → http://localhost:8080/myapp
myapp##2.war → http://localhost:8080/myapp (version 2, parallel deploy)
ROOT.war → http://localhost:8080/ (root context)
my#app.war → http://localhost:8080/my/app (nested path)
// Examples:
webapps/
├── ROOT.war → http://localhost:8080/
├── api.war → http://localhost:8080/api
├── admin.war → http://localhost:8080/admin
└── v2#api.war → http://localhost:8080/v2/api
Tomcat Architecture
Understanding Tomcat's internal architecture helps with configuration and troubleshooting:
// Tomcat Component Hierarchy
┌─────────────────────────────────────────────────────────────────────┐
│ SERVER │
│ (Top-level container - one per Tomcat instance) │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ SERVICE │ │
│ │ (Groups Connectors with an Engine) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ CONNECTOR │ │ CONNECTOR │ (Multiple connectors) │ │
│ │ │ (HTTP:8080) │ │ (HTTPS:8443)│ (HTTP, HTTPS, AJP) │ │
│ │ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ └────────┬───────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ ENGINE │ (Request processing) │ │
│ │ │ "Catalina" │ │ │
│ │ └────────┬────────┘ │ │
│ │ │ │ │
│ │ ┌────────▼────────┐ │ │
│ │ │ HOST │ (Virtual host: localhost) │ │
│ │ │ "localhost" │ (Can have multiple hosts) │ │
│ │ └────────┬────────┘ │ │
│ │ │ │ │
│ │ ┌─────────────┼─────────────┐ │ │
│ │ │ │ │ │ │
│ │ ▼ ▼ ▼ │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │CONTXT│ │CONTXT│ │CONTXT│ (Your applications) │ │
│ │ │/app1 │ │/app2 │ │ ROOT │ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Component Descriptions
| Component | Purpose | Configuration |
|---|---|---|
| Server | Top-level, represents entire Tomcat instance | server.xml (root element) |
| Service | Groups Connectors with one Engine | server.xml (<Service>) |
| Connector | Handles network connections (HTTP, HTTPS) | server.xml (<Connector>) |
| Engine | Processes requests, routes to correct Host | server.xml (<Engine>) |
| Host | Virtual host (domain handling) | server.xml (<Host>) |
| Context | Individual web application | context.xml, META-INF/context.xml |
Troubleshooting Common Issues
1. Tomcat Won't Start
# Check if port is already in use
lsof -i :8080 # Linux/Mac
netstat -ano | findstr 8080 # Windows
# Check logs for errors
tail -f logs/catalina.out
# Common causes:
# - Another Tomcat or app using port 8080
# - JAVA_HOME not set
# - Insufficient permissions
# - Corrupted WAR file
2. Application Not Loading
# Check application-specific log
tail -f logs/localhost.YYYY-MM-DD.log
# Check if WAR was extracted
ls -la webapps/
# Common causes:
# - Missing dependencies in WEB-INF/lib
# - web.xml errors
# - Jakarta vs javax package mismatch (Tomcat 10+)
# - Database connection failures
3. Out of Memory Errors
# Increase heap size in setenv.sh
CATALINA_OPTS="-Xms1024m -Xmx4096m"
# Check for memory leaks
# Manager app → "Find leaks" button
# Enable heap dump on OOM
CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=/opt/tomcat/logs/"
4. Slow Performance
# Increase thread pool
<Connector port="8080" maxThreads="500" />
# Enable connection pooling for database
# Check slow queries in application
# Monitor with JMX
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=9090"
Production Best Practices
Security:
- Remove default apps: Delete examples/, docs/, manager/ (or restrict access)
- Change shutdown port: Or disable it entirely
- Use HTTPS: Configure SSL/TLS connector
- Hide server info: Set
server="Apache"in Connector - Restrict manager access: IP-based restrictions in context.xml
Performance:
- Tune thread pool: Match maxThreads to expected load
- Enable compression: Add
compression="on"to Connector - Use NIO connector:
protocol="org.apache.coyote.http11.Http11NioProtocol" - Configure connection pooling: Proper min/max connections
Reliability:
- Set up monitoring: JMX, metrics endpoint, health checks
- Configure logging: Log rotation, appropriate log levels
- Graceful shutdown: Use proper shutdown scripts
- Backup configurations: Version control your conf/ directory
Summary
- Tomcat: World's most popular Java servlet container, open source, lightweight
- Directory Structure: webapps/ (apps), conf/ (config), logs/ (troubleshooting)
- Key Config Files: server.xml (main), tomcat-users.xml (auth), context.xml (resources)
- Deployment: Drop WAR in webapps/, use Manager, or Maven plugin
- Context Path: WAR filename determines URL (myapp.war → /myapp)
- Architecture: Server → Service → Connector + Engine → Host → Context
- Tomcat 10+: Uses jakarta.* packages (not javax.*)