server.xml Structure Analysis
server.xml is Tomcat's core configuration file that defines the entire server component hierarchy. Understanding this file gives you full control over ports, virtual hosts, and application contexts.
Overall Hierarchy
server.xml uses an XML tree structure to express Tomcat's component layers.
<Server> <!-- Top level: one JVM process -->
<Service> <!-- Group of connectors + engine -->
<Connector port="8080" .../> <!-- Request receiving port -->
<Connector port="8009" .../> <!-- AJP port (optional) -->
<Engine name="Catalina"> <!-- Request processing engine -->
<Host name="localhost"> <!-- Virtual host -->
<Context path="/" /> <!-- Web application -->
</Host>
</Engine>
</Service>
</Server>
Component Roles
| Component | Role | Key Attributes |
|---|---|---|
| Server | Represents the entire JVM instance | port (shutdown command port), shutdown |
| Service | Collection of connectors + engine | name |
| Connector | Receives network requests (HTTP/AJP) | port, protocol, maxThreads |
| Engine | Routes requests to Hosts | name, defaultHost |
| Host | Virtual host (domain-based routing) | name, appBase |
| Context | Web application path mapping | path, docBase |
Server Element
<Server port="8005" shutdown="SHUTDOWN">
| Attribute | Description | Default |
|---|---|---|
port | Port for receiving shutdown commands | 8005 |
shutdown | Shutdown command string | SHUTDOWN |
Security recommendation: Setting
port="-1"disables the shutdown port — useful to prevent remote shutdown command vulnerabilities.
<!-- Disable shutdown port (production recommended) -->
<Server port="-1" shutdown="SHUTDOWN">
Service Element
<Service name="Catalina">
<!-- Connectors and Engine are nested here -->
</Service>
Multiple Services can be registered inside one Server, but typically a single "Catalina" Service is used.
Engine Element
<Engine name="Catalina" defaultHost="localhost">
| Attribute | Description |
|---|---|
name | Engine identifier (used in logs) |
defaultHost | Default host when no Host matches |
jvmRoute | Sticky Session identifier in load-balanced clusters |
<!-- jvmRoute for cluster environments -->
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
Host Element
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
| Attribute | Description | Default |
|---|---|---|
name | Virtual host name (domain matching) | — |
appBase | Base directory for applications | webapps |
unpackWARs | Auto-extract WAR files | true |
autoDeploy | Auto-deploy WARs at runtime | true |
deployOnStartup | Auto-scan appBase on startup | true |
Multiple Virtual Hosts
<Engine name="Catalina" defaultHost="localhost">
<!-- Default host -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log"
suffix=".txt" pattern="%h %l %u %t "%r" %s %b"/>
</Host>
<!-- Additional virtual host -->
<Host name="api.example.com" appBase="/var/www/api"
unpackWARs="true" autoDeploy="false">
<Alias>api2.example.com</Alias>
</Host>
<Host name="admin.example.com" appBase="/var/www/admin"
unpackWARs="true" autoDeploy="false">
</Host>
</Engine>
Context Element
Context maps a specific web application to a URL path. It's recommended to use separate conf/Catalina/localhost/appname.xml files rather than embedding Context directly in server.xml.
<!-- Directly in server.xml (not recommended) -->
<Context path="/myapp" docBase="/var/www/myapp" reloadable="true"/>
<!-- Recommended: conf/Catalina/localhost/myapp.xml -->
Separate Context File (Recommended)
<!-- conf/Catalina/localhost/myapp.xml -->
<Context docBase="/var/www/myapp"
path="/myapp"
reloadable="false"
crossContext="false">
<!-- JNDI DataSource -->
<Resource name="jdbc/myDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"
username="dbuser"
password="dbpass"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb?useSSL=false"/>
</Context>
| Attribute | Description | Default |
|---|---|---|
path | URL context path | "" (ROOT) |
docBase | Actual file path | — |
reloadable | Auto-reload on class changes | false |
crossContext | Allow access from other contexts | false |
Production warning: Use
reloadable="true"only in development. It causes performance degradation in production.
GlobalNamingResources
Defines global JNDI resources (data sources, mail sessions, etc.).
<GlobalNamingResources>
<!-- User authentication DB (built-in) -->
<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"/>
<!-- Global JDBC DataSource -->
<Resource name="jdbc/globalDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://db-host:3306/mydb"
username="appuser"
password="secret"
maxTotal="50"
maxIdle="10"/>
</GlobalNamingResources>
Production server.xml Example
<?xml version="1.0" encoding="UTF-8"?>
<Server port="-1" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<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 name="Catalina">
<!-- HTTP/1.1 Connector -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="200"
minSpareThreads="10"
acceptCount="100"
enableLookups="false"
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/plain,text/css,application/json"/>
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D"/>
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false"
showServerInfo="false"/>
</Host>
</Engine>
</Service>
</Server>
Summary
| Component | Key Setting | Notes |
|---|---|---|
| Server | port="-1" (security) | Disable shutdown port in production |
| Host | autoDeploy="false" | Disable auto-deploy in production |
| Context | Separate XML file recommended | reloadable="false" in production |
| Engine | jvmRoute | Required for cluster Sticky Sessions |
| Realm | Wrap in LockOutRealm | Protects against brute-force attacks |