web.xml and Context Configuration
web.xml is the deployment descriptor for Java web applications, defining servlet mappings, filters, listeners, session settings, and more. Tomcat has two types: a global web.xml and an application-specific web.xml.
web.xml Hierarchy
$CATALINA_HOME/conf/web.xml ← Global defaults (provided by Tomcat)
↓ Override / merge
$APP/WEB-INF/web.xml ← Per-application configuration
The global web.xml is managed by Tomcat — avoid editing it directly. Most customization goes into the application's WEB-INF/web.xml.
Key Settings in Global web.xml
$CATALINA_HOME/conf/web.xml contains Tomcat's built-in servlets.
<!-- DefaultServlet — serves static files -->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value> <!-- Disable directory listing -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- JSP Servlet -->
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value> <!-- Hide X-Powered-By header -->
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
Application web.xml Structure
<?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_0.xsd"
version="6.0">
<display-name>My Application</display-name>
<!-- Global parameters -->
<context-param>
<param-name>applicationEnvironment</param-name>
<param-value>production</param-value>
</context-param>
</web-app>
Version note: From Tomcat 10, use the
jakarta.eenamespace. Tomcat 9 and below usejavax.servlet.
Servlet Registration and Mapping
<!-- Servlet definition -->
<servlet>
<servlet-name>ApiServlet</servlet-name>
<servlet-class>com.example.api.ApiServlet</servlet-class>
<init-param>
<param-name>maxRequestSize</param-name>
<param-value>10485760</param-value> <!-- 10MB -->
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<!-- URL mapping -->
<servlet-mapping>
<servlet-name>ApiServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
<!-- Spring MVC DispatcherServlet example -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Filter Registration
<!-- Character encoding filter -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- CORS filter -->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>https://example.com,https://www.example.com</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
Session Configuration
<session-config>
<session-timeout>30</session-timeout> <!-- minutes -->
<cookie-config>
<name>JSESSIONID</name>
<http-only>true</http-only> <!-- Block JavaScript access -->
<secure>true</secure> <!-- HTTPS only -->
<same-site>Strict</same-site> <!-- CSRF prevention (Servlet 6.0+) -->
</cookie-config>
<tracking-mode>COOKIE</tracking-mode> <!-- Disable URL session tracking -->
</session-config>
Security: Explicitly setting
<tracking-mode>COOKIE</tracking-mode>preventsjsessionid=xxxfrom being exposed in URLs. URL-based session tracking is vulnerable to session fixation attacks.
JNDI Resource Reference
<!-- Declare JNDI resource reference -->
<resource-ref>
<description>Production Database</description>
<res-ref-name>jdbc/myDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
The actual DataSource is defined in context.xml or server.xml's GlobalNamingResources.
// JNDI lookup in application code
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/myDB");
Connection conn = ds.getConnection();
Error Page Configuration
<!-- Error pages by HTTP status code -->
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<!-- Error pages by exception type -->
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/general.jsp</location>
</error-page>
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/error/db-error.jsp</location>
</error-page>
Security Constraints
<!-- Require authentication for specific URLs -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Admin Area</web-resource-name>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-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>
context.xml — Context-Specific Settings
<!-- WEB-INF/context.xml -->
<Context>
<!-- Session persistence (maintain sessions across restarts) -->
<Manager className="org.apache.catalina.session.PersistentManager"
maxIdleBackup="1">
<Store className="org.apache.catalina.session.FileStore"
directory="/var/tomcat-sessions"/>
</Manager>
<!-- Resource cache settings -->
<Resources cachingAllowed="true"
cacheMaxSize="100000"/>
</Context>
Summary
| File | Location | Role |
|---|---|---|
| Global web.xml | $CATALINA_HOME/conf/web.xml | Default servlets, default MIME types |
| App web.xml | $APP/WEB-INF/web.xml | Servlets, filters, sessions, security |
| Context XML | conf/Catalina/localhost/app.xml | App-specific Tomcat settings, DataSource |
| context.xml | conf/context.xml or WEB-INF/context.xml | Session persistence, resource cache |
| Session security | <tracking-mode>COOKIE</tracking-mode> | Prevent URL session exposure |
| JNDI DataSource | Context XML + <resource-ref> | Externalize DB connection pools |