This page covers common configuration steps for Apache Tomcat deployments.
Version: This guide covers Tomcat 9, 10, and 11. Configuration files are similar across versions, with some differences noted below.
| File | Purpose |
|---|---|
/opt/tomcat/conf/server.xml |
Main configuration - connectors, hosts, contexts |
/opt/tomcat/conf/tomcat-users.xml |
User authentication and roles |
/opt/tomcat/conf/web.xml |
Default servlet configuration |
/opt/tomcat/conf/context.xml |
Global context configuration |
/opt/tomcat/conf/logging.properties |
Java util logging configuration |
/opt/tomcat/bin/setenv.sh |
Environment variables (create if needed) |
/etc/systemd/system/tomcat.service |
systemd service configuration |
Edit the HTTP connector in server.xml:
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxParameterCount="1000"
maxPostSize="2097152"
compression="on"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json"
server="Apache"
xpoweredBy="false" />
Security attributes:
| Attribute | Recommended | Purpose |
|---|---|---|
maxParameterCount |
1000 |
Prevents DoS via excessive parameters |
maxPostSize |
2097152 (2MB) |
Limits POST size |
server |
Apache |
Hides Tomcat version |
xpoweredBy |
false |
Hides X-Powered-By header |
allowTrace |
false |
Prevents TRACE method XSS |
For direct HTTPS (if not using reverse proxy):
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLSv1.2"
sslEnabledProtocols="TLSv1.2,TLSv1.3"
ciphers="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"
useBodyEncodingForURI="true"
server="Apache"
xpoweredBy="false">
<SSLHostConfig>
<Certificate certificateKeystoreFile="/opt/tomcat/ssl/keystore.jks"
certificateKeystorePassword="CHANGE_THIS_PASSWORD"
type="RSA" />
</SSLHostConfig>
</Connector>
If using Apache httpd with mod_jk or mod_proxy_ajp:
<!-- Only enable if needed, and restrict to localhost or trusted IPs -->
<Connector port="8009"
protocol="AJP/1.3"
address="127.0.0.1"
redirectPort="8443"
secret="YOUR_STRONG_SECRET"
allowedRequestAttributesPattern=".*" />
Security Note: If you don’t need AJP, comment it out or remove it entirely.
Disable or secure the shutdown port:
<!-- Disable shutdown port -->
<Server port="-1" shutdown="SHUTDOWN">
<!-- Or use a strong password -->
<Server port="8005" shutdown="VERY_STRONG_RANDOM_PASSWORD">
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="false"
deployOnStartup="false"
deployXML="false">
<!-- 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 %D "%{User-Agent}i"" />
<!-- Error reporting (hide server info) -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showServerInfo="false"
showReport="false" />
<!-- Remote address filtering for admin apps -->
<!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1|::1|YOUR_ADMIN_IP" /> -->
</Host>
Configure users and roles for Manager access:
<tomcat-users>
<!-- Manager roles -->
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<role rolename="manager-status"/>
<!-- Host Manager roles -->
<role rolename="admin-gui"/>
<role rolename="admin-script"/>
<!-- Admin user -->
<user username="admin"
password="STRONG_PASSWORD_HERE"
roles="manager-gui,manager-script,admin-gui"/>
<!-- Manager-only user -->
<user username="manager"
password="ANOTHER_STRONG_PASSWORD"
roles="manager-gui,manager-status"/>
</tomcat-users>
Edit /opt/tomcat/webapps/manager/META-INF/context.xml:
<Context>
<!-- Restrict access to specific IPs -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|YOUR_ADMIN_IP_1|YOUR_ADMIN_IP_2" />
<!-- Session configuration -->
<Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.realm\.GenericPrincipal\$SerializablePrincipal|\[Ljava.lang.String;"
warnOnSessionAttributeFilterFailure="true"/>
</Context>
Edit /opt/tomcat/webapps/host-manager/META-INF/context.xml:
<Context>
<!-- Restrict access to specific IPs -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|YOUR_ADMIN_IP_1|YOUR_ADMIN_IP_2" />
</Context>
Create /opt/tomcat/bin/setenv.sh:
#!/bin/bash
# Memory settings
JAVA_OPTS="$JAVA_OPTS -Xms512m -Xmx2g"
JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=512m"
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
# Temporary directory
JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=/opt/tomcat/temp"
# Security settings
JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
# Character encoding
JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"
# Server name (hide version)
JAVA_OPTS="$JAVA_OPTS -Dserver.name=Apache"
export JAVA_OPTS
Make it executable:
chmod +x /opt/tomcat/bin/setenv.sh
In /etc/systemd/system/tomcat.service:
[Service]
Environment=JAVA_HOME=/usr/lib/jvm/java-17-openjdk
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=JAVA_OPTS="-Xms512m -Xmx2g -XX:MaxMetaspaceSize=512m"
Edit /opt/tomcat/conf/logging.properties:
# Global logging level
.level = INFO
# Console handler
handlers = java.util.logging.ConsoleHandler, org.apache.juli.FileHandler
# Console handler settings
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
# File handler settings
org.apache.juli.FileHandler.level = FINE
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = tomcat
org.apache.juli.FileHandler.suffix = .log
org.apache.juli.FileHandler.encoding = UTF-8
# Specific logger levels
org.apache.catalina.level = INFO
org.apache.coyote.level = INFO
org.apache.jasper.level = INFO
In server.xml Host configuration:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D "%{User-Agent}i" %I %S"
rotate="true"
maxDays="90" />
Pattern variables:
| Variable | Description |
|---|---|
%h |
Remote host/IP |
%l |
Remote logname (usually -) |
%u |
Remote user (if authenticated) |
%t |
Timestamp |
%r |
Request line |
%s |
Status code |
%b |
Response size |
%D |
Time in microseconds |
%T |
Time in seconds |
%I |
Thread name |
%S |
Session ID |
Create /opt/tomcat/conf/Catalina/localhost/yourapp.xml:
<Context docBase="/path/to/your/application"
path="/yourapp"
crossContext="false"
privileged="false"
allowLinking="false">
<!-- Resource links -->
<Resource name="jdbc/YourDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/yourdb"
username="dbuser"
password="dbpassword"
maxTotal="20"
maxIdle="10"
maxWaitMillis="-1"/>
<!-- Environment variables -->
<Environment name="app/config"
type="java.lang.String"
value="production"
override="false"/>
</Context>
In server.xml Host element:
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="false" <!-- Disable in production -->
deployOnStartup="false" <!-- Disable in production -->
deployXML="false"> <!-- Disable context.xml auto-deployment -->
In server.xml:
<Engine name="Catalina" defaultHost="www.example.com">
<Host name="www.example.com"
appBase="/var/www/example"
unpackWARs="true"
autoDeploy="false">
<Alias>example.com</Alias>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="example_access_log"
suffix=".txt"
pattern="common" />
</Host>
<Host name="www.other.com"
appBase="/var/www/other"
unpackWARs="true"
autoDeploy="false">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="other_access_log"
suffix=".txt"
pattern="common" />
</Host>
</Engine>
After making configuration changes:
# Test configuration syntax
sudo /opt/tomcat/bin/catalina.sh configtest
# Restart Tomcat
sudo systemctl restart tomcat
# Check status
sudo systemctl status tomcat
# View logs
sudo tail -f /opt/tomcat/logs/catalina.out
# Check if Tomcat is running
sudo systemctl is-active tomcat
# Check listening ports
sudo ss -tlnp | grep java
# Test HTTP connector
curl -I http://localhost:8080
# Check logs for errors
grep -i "error\|exception\|fatal" /opt/tomcat/logs/catalina.out | tail -20
# Verify Manager app access
curl -u admin:password http://localhost:8080/manager/status
When upgrading between major versions:
javax.* → jakarta.*)Any questions?
Feel free to contact us. Find all contact information on our contact page.