Apache Tomcat
Open-source Java web application server implementing Jakarta EE specifications. Pure Java HTTP web server environment. Lightweight and efficient execution.
Application Server
Apache Tomcat
Overview
Apache Tomcat is an open-source implementation of Jakarta EE specifications, providing a pure Java HTTP web server environment for running Java-based web applications. As a leading servlet container, Tomcat serves as the backbone for countless Java web applications worldwide. It offers comprehensive support for servlets, JSP (JavaServer Pages), and WebSocket technologies while maintaining lightweight performance and enterprise-grade reliability. Tomcat's modular architecture and extensive configuration options make it the preferred choice for deploying Java web applications in both development and production environments.
Details
Apache Tomcat 2025 edition continues its leadership as the industry-standard servlet container, supporting the latest Jakarta EE specifications with continuous updates for enhanced security and performance. With over two decades of development, Tomcat has evolved into a mature, stable platform trusted by enterprises globally. The server provides robust support for modern Java features including virtual threads, HTTP/2, and WebSocket protocols. Tomcat's architecture emphasizes simplicity and efficiency, offering extensive customization through XML configuration files and programmatic deployment options. It seamlessly integrates with popular development frameworks like Spring, Struts, and Hibernate, making it an essential component of the Java enterprise ecosystem.
Key Features
- Jakarta EE Compliance: Full implementation of Servlet, JSP, and WebSocket specifications
- Pure Java Implementation: Cross-platform compatibility with JVM-based deployment
- Lightweight Architecture: Minimal resource footprint with modular component design
- Hot Deployment: Dynamic application deployment without server restart
- Management Tools: Comprehensive web-based administration interface
- Clustering Support: Built-in session clustering and load balancing capabilities
Advantages and Disadvantages
Advantages
- Industry-standard servlet container with extensive documentation and community support
- Excellent integration with Java development tools and popular frameworks
- Robust performance with optimized thread pooling and connection management
- Comprehensive security features with configurable authentication and authorization
- Hot deployment capabilities for efficient development and production workflows
- Strong enterprise adoption with proven scalability in large-scale deployments
- Active development with regular security updates and feature enhancements
Disadvantages
- Java-specific deployment requiring JVM installation and configuration
- Memory overhead can be significant for simple web applications
- Configuration complexity may be overwhelming for basic deployment scenarios
- Performance can be affected by Java garbage collection patterns
- Limited static content serving capabilities compared to dedicated web servers
- Requires understanding of Java EE concepts for optimal configuration
Reference Links
Configuration Examples
Installation and Basic Setup
# Download and extract Tomcat
wget https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.34/bin/apache-tomcat-10.1.34.tar.gz
tar -xzf apache-tomcat-10.1.34.tar.gz
mv apache-tomcat-10.1.34 /opt/tomcat
# Set environment variables
export CATALINA_HOME=/opt/tomcat
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
# Create tomcat user (recommended for security)
sudo useradd -r -m -U -d /opt/tomcat -s /bin/false tomcat
sudo chown -R tomcat:tomcat /opt/tomcat
# Set executable permissions
chmod +x $CATALINA_HOME/bin/*.sh
# Start Tomcat
$CATALINA_HOME/bin/startup.sh
# Check Tomcat status
$CATALINA_HOME/bin/catalina.sh version
# Stop Tomcat
$CATALINA_HOME/bin/shutdown.sh
Server Configuration (server.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<!-- Global JNDI resources -->
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- Service with HTTP and HTTPS connectors -->
<Service name="Catalina">
<!-- HTTP Connector -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="200"
minSpareThreads="10"
enableLookups="false"
acceptCount="100"
debug="0"
URIEncoding="UTF-8"
compression="on"
compressionMinSize="1024"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript" />
<!-- HTTPS Connector -->
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
connectionTimeout="20000"
acceptCount="100">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
<!-- AJP Connector for Apache integration -->
<Connector protocol="AJP/1.3"
address="0.0.0.0"
port="8009"
redirectPort="8443"
secretRequired="false" />
<!-- Engine configuration -->
<Engine name="Catalina" defaultHost="localhost">
<!-- Realm for authentication -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<!-- Default virtual host -->
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true">
<!-- Access log configuration -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"" />
<!-- Security valve for remote access restriction -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1|192\.168\..*|10\..*" />
</Host>
<!-- Additional virtual host example -->
<Host name="example.com"
appBase="webapps-example"
unpackWARs="true"
autoDeploy="true">
<Context path="" docBase="ROOT" />
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="example_access_log"
suffix=".txt"
pattern="combined" />
</Host>
</Engine>
</Service>
</Server>
Web Application Deployment Descriptor (web.xml)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd"
version="6.1">
<display-name>My Web Application</display-name>
<description>
Enterprise web application with servlet and JSP support
</description>
<!-- Context parameters -->
<context-param>
<param-name>application.environment</param-name>
<param-value>production</param-value>
</context-param>
<context-param>
<param-name>database.url</param-name>
<param-value>jdbc:postgresql://localhost:5432/myapp</param-value>
</context-param>
<!-- Servlet definitions -->
<servlet>
<servlet-name>ControllerServlet</servlet-name>
<servlet-class>com.example.controller.ControllerServlet</servlet-class>
<init-param>
<param-name>configFile</param-name>
<param-value>/WEB-INF/controller-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>ApiServlet</servlet-name>
<servlet-class>com.example.api.ApiServlet</servlet-class>
<multipart-config>
<max-file-size>52428800</max-file-size> <!-- 50MB -->
<max-request-size>104857600</max-request-size> <!-- 100MB -->
<file-size-threshold>1048576</file-size-threshold> <!-- 1MB -->
</multipart-config>
</servlet>
<!-- Servlet mappings -->
<servlet-mapping>
<servlet-name>ControllerServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ApiServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- Filter definitions -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.example.filters.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>com.example.filters.SecurityFilter</filter-class>
</filter>
<!-- Filter mappings -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>/secure/*</url-pattern>
</filter-mapping>
<!-- Session configuration -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
<same-site>strict</same-site>
</cookie-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
<!-- Welcome files -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- Error pages -->
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/general.jsp</location>
</error-page>
<!-- Security constraints -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Pages</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/login-error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
Context Configuration (context.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Database connection pool -->
<Resource name="jdbc/MyDatabase"
auth="Container"
type="javax.sql.DataSource"
maxTotal="20"
maxIdle="10"
maxWaitMillis="10000"
username="dbuser"
password="dbpass"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/myapp"
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="300000"
minEvictableIdleTimeMillis="600000" />
<!-- JMS Connection Factory -->
<Resource name="jms/ConnectionFactory"
auth="Container"
type="org.apache.activemq.ActiveMQConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://localhost:61616" />
<!-- Mail Session -->
<Resource name="mail/Session"
auth="Container"
type="jakarta.mail.Session"
mail.smtp.host="smtp.example.com"
mail.smtp.port="587"
mail.smtp.auth="true"
mail.smtp.starttls.enable="true"
mail.smtp.user="[email protected]"
password="emailpass" />
<!-- Environment entries -->
<Environment name="app/maxUsers"
value="100"
type="java.lang.Integer" />
<Environment name="app/applicationName"
value="My Application"
type="java.lang.String" />
<!-- Security constraints for manager access -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1|192\.168\..*" />
<!-- Session manager configuration -->
<Manager className="org.apache.catalina.session.PersistentManager"
saveOnRestart="true"
maxActiveSession="-1"
minIdleSwap="5"
maxIdleSwap="10"
maxIdleBackup="30">
<Store className="org.apache.catalina.session.FileStore"
directory="/tmp/tomcat-sessions" />
</Manager>
</Context>
User Management (tomcat-users.xml)
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<!-- Define roles -->
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<!-- Manager user for web interface -->
<user username="manager"
password="s3cr3tP@ssw0rd"
roles="manager-gui,manager-script,manager-jmx,manager-status"/>
<!-- Admin user for full access -->
<user username="admin"
password="@dm1nP@ssw0rd"
roles="admin-gui,admin-script,manager-gui,manager-script,manager-jmx,manager-status"/>
<!-- Application users -->
<user username="appuser"
password="appP@ss123"
roles="user"/>
<user username="poweruser"
password="p0w3rUs3r!"
roles="user,poweruser"/>
</tomcat-users>
Logging Configuration (logging.properties)
# Global logging configuration
handlers = java.util.logging.ConsoleHandler, org.apache.juli.FileHandler
.level = INFO
# Console handler configuration
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
# File handler configuration
org.apache.juli.FileHandler.level = INFO
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = catalina.
org.apache.juli.FileHandler.suffix = .log
org.apache.juli.FileHandler.formatter = org.apache.juli.OneLineFormatter
# Facility specific loggers
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = org.apache.juli.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = org.apache.juli.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = org.apache.juli.FileHandler
# Host manager specific logger
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
# Application specific logger
com.example.myapp.level = DEBUG
com.example.myapp.handlers = org.apache.juli.FileHandler
Environment Configuration (setenv.sh)
#!/bin/bash
# Java heap settings
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx2048m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=256m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=512m"
# Garbage collection settings
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseStringDeduplication"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockExperimentalVMOptions"
# JVM tuning for web applications
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseCompressedOops"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+OptimizeStringConcat"
# Remote debugging (development only)
# export CATALINA_OPTS="$CATALINA_OPTS -Xdebug"
# export CATALINA_OPTS="$CATALINA_OPTS -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
# JMX monitoring
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=9999"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
# Security settings
export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.egd=file:/dev/./urandom"
# Application-specific settings
export CATALINA_OPTS="$CATALINA_OPTS -Dapp.environment=production"
export CATALINA_OPTS="$CATALINA_OPTS -Dfile.encoding=UTF-8"
export CATALINA_OPTS="$CATALINA_OPTS -Duser.timezone=UTC"
# Security manager (optional)
# export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.manager"
# export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.policy=$CATALINA_BASE/conf/catalina.policy"
# Set environment variables
export JAVA_HOME="/usr/lib/jvm/java-17-openjdk"
export CATALINA_PID="$CATALINA_BASE/tomcat.pid"
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"
# Umask for security
umask 0027
Performance Monitoring and Management
#!/bin/bash
# JVM monitoring with JConsole
jconsole localhost:9999
# Thread dump for debugging
$JAVA_HOME/bin/jstack $(cat $CATALINA_PID)
# Heap dump for memory analysis
$JAVA_HOME/bin/jmap -dump:format=b,file=heapdump.hprof $(cat $CATALINA_PID)
# Application deployment via Manager API
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/text/deploy?path=/myapp&war=file:/path/to/myapp.war"
# List deployed applications
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/text/list"
# Reload application
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/text/reload?path=/myapp"
# Application status
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/text/sessions?path=/myapp"
# Server status (requires manager-status role)
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/status/all"
# Undeploy application
curl -u manager:s3cr3tP@ssw0rd \
"http://localhost:8080/manager/text/undeploy?path=/myapp"