First time here?

» Overview of all topics you'll find quick start solutions for here

» Cherry-picked developer resources for you: Java, Java EE, Spring Framework

» Testing Spring Boot Applications Masterclass

Tired of text/plain ? Have a look at my online courses or YouTube channel for more Java, Spring Framework & Jakarta EE content.

With the presence of Docker, Kubernetes and cheaper hardware, the deployment model of multiple applications inside one application server has passed. Now, you deploy one Jakarta EE application to one application server. This eliminates the need for different context paths. You can use the root context / for your Jakarta EE application. With this blog post, you'll learn how to achieve this for each Jakarta EE application server.

The default behavior for Jakarta EE application server

Without any further configuration, most of the Jakarta EE application servers deploy the application to a context path based on the filename of your .war . If you e.g. deploy your my-banking-app.war application, the server will use the context prefix /my-banking-app for your application. All you JAX-RS endpoints, Servlets, .jsp , .xhtml content is then available below this context, e.g /my-banking-app/resources/customers .

This was important in the past, where you deployed multiple applications to one application server. Without the context prefix, the application server wouldn't be able to route the traffic to the correct application.

As of today, the deployment model changed with Docker, Kubernetes and cheaper infrastructure. You usually deploy one .war within one application server running as a Docker container. Given this deployment model, the context prefix is irrelevant. Mapping the application to the root context / is more convenient.

If you configure a reverse proxy or an Ingress controller (in the Kubernetes world), you are happy if you can just route to / instead of remembering the actual context path (error-prone).

Deploying to root context: Payara & Glassfish

As Payara is a fork of Glassfish, the configuration for both is quite similar. The most convenient way for Glassfish is to place a glassfish-web.xml file in the src/main/webapp/WEB-INF folder of your application:

<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app> <context-root>/</context-root> </glassfish-web-app> 1 2 3 4 5 <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app> <context-root> / </context-root> </glassfish-web-app>

For Payara the filename is payara-web.xml :

<!DOCTYPE payara-web-app PUBLIC "-//Payara.fish//DTD Payara Server 4 Servlet 3.0//EN" "https://raw.githubusercontent.com/payara/Payara-Server-Documentation/master/schemas/payara-web-app_4.dtd"> <payara-web-app> <context-root>/</context-root> </payara-web-app> 1 2 3 4 <!DOCTYPE payara-web-app PUBLIC "-//Payara.fish//DTD Payara Server 4 Servlet 3.0//EN" "https://raw.githubusercontent.com/payara/Payara-Server-Documentation/master/schemas/payara-web-app_4.dtd"> <payara-web-app> <context-root> / </context-root> </payara-web-app>

Both also support configuring the context path of the application within their admin console. IMHO this less convenient than the .xml file solution.

Deploying to root context: Open Liberty

Open Liberty also parses a proprietary web.xml file within src/main/webapp/WEB-INF : ibm-web-ext.xml

<web-ext xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-ext_1_0.xsd" version="1.0"> <context-root uri="/"/> </web-ext> 1 2 3 4 5 6 7 <web-ext xmlns = "http://websphere.ibm.com/xml/ns/javaee" xmlns : xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi : schemaLocation = "http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-ext_1_0.xsd" version = "1.0" > <context-root uri = "/" /> </web-ext>

Furthermore, you can also configure the context of your application within your server.xml :

<server> <featureManager> <feature>servlet-4.0</feature> </featureManager> <httpEndpoint id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443"/> <webApplication location="app.war" contextRoot="/" name="app"/> </server> 1 2 3 4 5 6 7 8 9 <server> <featureManager> <feature> servlet-4.0 </feature> </featureManager> <httpEndpoint id = "defaultHttpEndpoint" httpPort = "9080" httpsPort = "9443" /> <webApplication location = "app.war" contextRoot = "/" name = "app" /> </server>

Deploying to root context: WildFly

WildFly also has two simple ways of configuring the root context for your application. First, you can place a jboss-web.xml within src/main/webapp/WEB-INF :

<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd"> <jboss-web> <context-root>/</context-root> </jboss-web> 1 2 3 4 <!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd"> <jboss-web> <context-root> / </context-root> </jboss-web>

Second, while copying your .war file to your Docker container, you can name it ROOT.war :

FROM jboss/wildfly ADD target/app.war /opt/jboss/wildfly/standalone/deployments/ROOT.war 1 2 FROM jboss/wildfly ADD target/app . war /opt/jboss/wildfly/standalone/deployments/ROOT . war

For more tips & tricks for each application server, have a look at my cheat sheet.

Have fun deploying your Jakarta EE applications to the root context,

Phil