When deploying Tomcat 6.x on Debian Lenny, the first step is proper filesystem isolation. Create a dedicated system user with minimal privileges:
# Create jakarta user with no login shell
sudo useradd -r -s /bin/false jakarta
Set strict directory permissions (adjust paths based on your installation):
sudo chown -R jakarta:jakarta /opt/tomcat
sudo chmod -R 750 /opt/tomcat
sudo chmod 750 /opt/tomcat/conf
sudo chmod 640 /opt/tomcat/conf/*
Delete all sample applications that ship with Tomcat:
rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
rm -rf /opt/tomcat/webapps/manager
rm -rf /opt/tomcat/webapps/host-manager
For production deployments, consider removing the ROOT webapp as well and deploying your application as the root context.
Key configuration changes in server.xml
:
<Connector port="8080" protocol="HTTP/1.1"
address="127.0.0.1"
maxThreads="150"
minSpareThreads="25"
enableLookups="false"
acceptCount="100"
disableUploadTimeout="true"/>
In web.xml
, add these security constraints:
<security-constraint>
<web-resource-collection>
<web-resource-name>Restricted Methods</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
Enabling the Security Manager adds significant protection. Add to catalina.sh
:
export CATALINA_OPTS="$CATALINA_OPTS -Djava.security.manager -Djava.security.policy==$CATALINA_BASE/conf/catalina.policy"
Example policy file entries:
// Basic permissions for all webapps
grant {
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.class.version", "read";
};
// Specific permissions for your application
grant codeBase "file:${catalina.base}/webapps/your-app/-" {
permission java.io.FilePermission "${catalina.base}/webapps/your-app/-", "read,write";
permission java.net.SocketPermission "db.yourdomain.com:3306", "connect";
};
For production deployments, running Tomcat behind Apache with mod_jk
is recommended over mod_proxy
for better performance and control. Example workers.properties
:
worker.list=loadbalancer
worker.node1.port=8009
worker.node1.host=localhost
worker.node1.type=ajp13
worker.node1.lbfactor=1
worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=node1
In httpd.conf
:
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
JkMount /* loadbalancer
- Implement regular log monitoring for suspicious activity
- Set up HTTPS using APR or a reverse proxy
- Regularly apply security patches (consider upgrading to a supported Tomcat version)
- Implement fail2ban for repeated failed login attempts
- Disable server signature in HTTP headers
Running Tomcat as a non-root user (like your 'jakarta' user) is a great first step. Here's how to properly configure permissions:
# Directory structure recommendation
chown -R jakarta:jakarta /opt/tomcat
chmod -R 750 /opt/tomcat
find /opt/tomcat/conf -type f -exec chmod 640 {} \;
find /opt/tomcat/bin -type f -name "*.sh" -exec chmod 750 {} \;
All default webapps should be removed as they contain vulnerabilities:
rm -rf /opt/tomcat/webapps/docs
rm -rf /opt/tomcat/webapps/examples
rm -rf /opt/tomcat/webapps/manager
rm -rf /opt/tomcat/webapps/host-manager
Key modifications needed in server.xml:
<Connector port="8080" protocol="HTTP/1.1"
address="127.0.0.1"
maxHttpHeaderSize="8192"
maxThreads="150"
minSpareThreads="25"
enableLookups="false"
acceptCount="100"
disableUploadTimeout="true" />
Enabling the Security Manager adds an important layer of protection. Add this to catalina.sh:
JAVA_OPTS="$JAVA_OPTS -Djava.security.manager -Djava.security.policy==$CATALINA_BASE/conf/catalina.policy"
Sample policy file entries:
// Required permissions
grant codeBase "file:${catalina.home}/bin/-" {
permission java.security.AllPermission;
};
// Web application permissions (restrictive)
grant codeBase "file:${catalina.home}/webapps/your-app/-" {
permission java.io.FilePermission "${catalina.home}/webapps/your-app/-", "read,write";
permission java.lang.RuntimePermission "getClassLoader";
};
Using mod_proxy is simpler than mod_jk for most cases. Example configuration:
<VirtualHost *:80>
ServerName yourdomain.com
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
ProxyPreserveHost On
<Proxy *>
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Proxy>
</VirtualHost>
- Set secure and httpOnly flags for cookies in context.xml
- Disable TRACE and OPTIONS methods in web.xml
- Implement CSRF protection for web applications
- Regularly update Java and Tomcat with security patches
Example web.xml configuration for disabling TRACE:
<security-constraint>
<web-resource-collection>
<web-resource-name>Disable TRACE</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint />
</security-constraint>