How to deploy a Spring Boot WAR to Wildfly, JBoss or Tomcat

This is a short guide on how to deploy a Spring boot war packaged application to Wildfly and Tomcat. As you know, Wildfly is the name of the community version of JBoss EAP, so this configuration should work for JBoss EAP as well.

Introduction

Updated: Code examples use Wildfly 18, Java 11 and Spring Boot 2.2. More info about code examples.

Spring Boot guides encourage you to deploy your application with the embedded server when you package the jar file. The default server depends now on which web technology you use. If you include the dependency spring-boot-starter-web, Spring Boot includes Tomcat by default. For WebFlux (spring-boot-starter-webflux), Reactor Netty is the default embedded server.

Having a default embedded server is really handy, but sometimes you need to deploy your application to an existing application server such as WildflyJBoss EAP or Tomcat and, for that, you need a deployable WAR file.

Preparing your Spring Boot app to deploy it to JBoss Wildfly

All the code in this post is available on GitHub: Spring Boot JBoss Wildfly. If you find it useful, please give it a star!

In order to make it work, you have to follow some easy steps.

  1. First, go to your application’s main class and make it extend SpringBootServletInitializer. Note that, if you prefer to work with Spring Boot version 1.5 or earlier, this class was moved to a different package in Spring Boot 2:
    1. org.springframework.boot.web.support.SpringBootServletInitializer: if you use Spring Boot 1.5
    2. org.springframework.boot.web.servlet.support.SpringBootServletInitializer: if you use Spring Boot 2
  2. Override the configure method and point your sources to this same class (it’s the entry point of your application). Use the passed argument, SpringApplicationBuilder. If you don’t do that, your different components won’t be detected, won’t be injected in the context so your application won’t work.
@SpringBootApplication
public class JbossWildflyDemoApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(JbossWildflyDemoApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(JbossWildflyDemoApplication.class, args);
    }
}
  1. Now you should write some additional configuration in your Maven pom.xml file. Apart from changing the packaging method to generate a Spring Boot war package, you can exclude now the embedded tomcat server (you don’t need it) and specify a provided dependency with the javax.servlet API.
<project ...>
  ...
  <packaging>war</packaging>
  ...
  <build>
    <plugins>
      <!-- OPTIONAL: Remove this plugin to reduce the WAR file size.
           It's not needed to deploy in an external application server. -->
      <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    ...
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <!-- We need to include the javax.servlet API specs, the implementation 
         will be provided by Wildfly / JBoss / Tomcat -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <scope>provided</scope>
    </dependency>
...
</project>
  1. As you can see in the notes above, you can even remove the spring-boot-maven-plugin plugin , since you don’t need it when deploying on the external server. This will save you some extra megabytes in the WAR file.
Get the book Practical Software Architecture

Note that you can also choose to specify the spring-boot-starter-tomcat as provided, instead of excluding it from the starter web artifact. If you do that, you don’t need the javax.servlet-api artifact to build your application. However, the alternative we follow within this post saves us some megabytes in the resulting WAR file.

Creating a Dockerfile to deploy the app to Wildfly

You can find a Dockerfile and a bash script with the sources. The Docker image is based on the official one with OpenJDK 11 and Wildfly 18: jboss/wildfly:18.0.0.Final.

In the Dockerfile, you just need to copy the deployable spring boot war file into the deployments folder of the Wildfly server, which will take care of the rest and serve our application. To give it a friendlier name to the context, you can rename the file when copying it. By default, the base image we’re using also exposes the default web port of Wildfly, 8080.

# This official image uses OpenJDK 11 and Wildfly 18
FROM jboss/wildfly:18.0.0.Final

# Copy the war file to the deployments folder
COPY target/jboss-wildfly-demo-1.0.0-SNAPSHOT.war 
     /opt/jboss/wildfly/standalone/deployments/jboss-wildfly-demo.war

Testing our Wildfly Spring Boot application with Docker

To compile the sources and build the images you can use the script docker-build.sh in the Github repository, or follow these steps:

  1. Compile and package the app with the maven wrapper using ./mvnw clean package. You need to have a JDK 11 or above installed.
  2. Create the Docker image with docker build -t wildfly-springboot-app:1.0 .

With the -t flag, you assign a tag to the docker image so it’s easier to identify. Now we can run a container, exposing the port 8080 so it’s accessible from your host:

$ docker run -p 8080:8080 -it wildfly-springboot-app

Then you can access our application’s REST API by navigating to this URL with your browser: http://localhost:8080/jboss-wildfly-demo/hola

Using HTTPie:

$ http :8080/jboss-wildfly-demo/hola 
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 11
Content-Type: text/plain;charset=UTF-8

Hola Amigo!

Note that jboss-wildfly-demo is the name of the file we used when copying the war file. This is what Wildfly will use to create the context for the web application. Also, if you’re running Docker with a different host IP, you may need to change localhost for that specific host.

Deploying the Spring Boot app to Tomcat without embedded server

We’ve been using Wildfly as the example through this article but the instructions to deploy to Tomcat are exactly the same. To prove it, you can find a different Dockerfile in the repo that deploys the application to a Tomcat 9 container:

# This is the official image for Tomcat 9.x and OpenJDK 11
FROM tomcat:9-jdk11-openjdk-slim

# Copy the war file to the deployments folder
COPY target/jboss-wildfly-demo-1.0.0-SNAPSHOT.war 
     /usr/local/tomcat/webapps/tomcat-demo.war

In this case, we use the file name tomcat-demo so that will be our application context in Tomcat. We build this new image using a different Dockerfile name:

$ docker build -t tomcat-app:1.0 -f ./Dockerfile-tomcat .

And we run a container the same way as before. Remember to stop the previous one so you can use the same port number:

$ docker run -p 8080:8080 -it tomcat-app:1.0

You’ll see the “Hola Amigo!” message this time when you navigate to http://localhost:8080/tomcat-demo/hola.

Any feedback or improvement suggestions? Do that via GitHub: https://github.com/mechero/spring-boot-jboss-wildfly

Developing Web Applications with Spring Boot? Have a look at my book: Learn Microservices with Spring Boot 
Moisés Macero's Picture

About Moisés Macero

Software Developer, Architect, and Author.
Do you need help?

Amsterdam, The Netherlands https://thepracticaldeveloper.com