Deploying Java Applications to Tomcat via Jenkins
Building a WAR file is only half the job. The other half is getting that WAR file onto a server where it can actually run and serve users. That server, for Java web applications, is Apache Tomcat. In this post, we will set up Tomcat on a dedicated EC2 instance, configure it for Jenkins access, install the deployment plugin, and write the pipeline code to automate the entire deployment process.

The Deployment Architecture
At this point in our CI/CD pipeline, here is what we have:
Developer pushes code to GitHub.
Jenkins pulls the code, Maven builds it, and a WAR file is generated in the workspace.
What we need to add:
Jenkins takes the WAR file and deploys it to a Tomcat server running on a separate EC2 instance.
Users access the application through Tomcat.
The Tomcat server is a separate machine from Jenkins. This is the correct way to set up a deployment environment -- you do not run your application on the same server as your CI tool.
Setting Up Tomcat Automatically with a Script
Previously, the Tomcat setup was done manually step by step. For efficiency, the entire setup is captured in a shell script (tomcat.sh). Let us walk through what it does so you understand each step, even when running it automatically.
#!/bin/bash
# Install Java 21 (required by Tomcat)
dnf install java-21-amazon-corretto -y
# Download Tomcat 11
wget https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.14/bin/apache-tomcat-11.0.14.tar.gz
# Extract it
tar -zxvf apache-tomcat-11.0.14.tar.gz
# Add the manager-gui role
sed -i '56 a\<role rolename="manager-gui"/>' apache-tomcat-11.0.14/conf/tomcat-users.xml
# Add the manager-script role
sed -i '57 a\<role rolename="manager-script"/>' apache-tomcat-11.0.14/conf/tomcat-users.xml
# Add a user with both roles
sed -i '58 a\<user username="BHATTU" password="BHATTU" roles="manager-gui, manager-script"/>' apache-tomcat-11.0.14/conf/tomcat-users.xml
# Close the tomcat-users block properly
sed -i '59 a\</tomcat-users>' apache-tomcat-11.0.14/conf/tomcat-users.xml
# Remove the closing tag that was already there to avoid duplication
sed -i '56d' apache-tomcat-11.0.14/conf/tomcat-users.xml
# Remove the IP restriction lines from the Manager app context
sed -i '21d' apache-tomcat-11.0.14/webapps/manager/META-INF/context.xml
sed -i '22d' apache-tomcat-11.0.14/webapps/manager/META-INF/context.xml
# Start Tomcat
sh apache-tomcat-11.0.14/bin/startup.sh
Let us unpack the important parts.
Why We Edit tomcat-users.xml
By default, Tomcat has no users configured. The Manager application (which lets you deploy, undeploy, and manage web applications) is locked down. Jenkins needs a user account with the right roles to deploy WAR files through the Manager API.
The two roles we add are:
manager-gui-- allows access to the Tomcat Manager web interface in the browser.manager-script-- allows programmatic access (via HTTP API), which is how Jenkins deploys WAR files.
The user we create (BHATTU with password BHATTU in this example) gets both roles. You should use a stronger username and password in any real environment.
Why We Edit context.xml
Tomcat's Manager application has a built-in restriction that only allows connections from localhost (IP address 127.0.0.1). This is a security default.
The lines we delete from webapps/manager/META-INF/context.xml are:
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
Removing these lines allows connections from any IP address, including the Jenkins server. Without this change, Jenkins would get a 403 Forbidden error every time it tried to deploy.
Running the Setup Script
On your Tomcat EC2 instance (a fresh Amazon Linux 2 machine):
chmod +x tomcat.sh
sudo bash tomcat.sh
Important: Check the current Tomcat version on the Apache Tomcat download page. The script uses 11.0.14 -- if a newer patch version is available, update the version number in the script accordingly before running it.
After the script finishes, you will see:
Tomcat started.
Verifying Tomcat Is Running
Take the public IP of your Tomcat EC2 instance and open it in a browser:
http://<tomcat-ec2-public-ip>:8080
You should see the Tomcat welcome page. Click Manager App and enter the username (BHATTU) and password (BHATTU). You will see the Tomcat Web Application Manager, which lists all deployed applications.
This is where our WAR file will appear after Jenkins deploys it.
Installing the Deploy to Container Plugin in Jenkins
Jenkins does not know how to talk to Tomcat's deployment API natively. We need a plugin.
Go to Manage Jenkins.
Click Plugins.
Click Available plugins.
Search for
Deploy to container.Select Deploy to container Plugin.
Click Install.
Check Restart Jenkins when installation is complete.
This plugin adds a new post-build action (and a new pipeline step) that Jenkins can use to deploy WAR files to Tomcat, JBoss, and other Java application servers.
Adding Tomcat Credentials to Jenkins
Jenkins needs to authenticate with Tomcat's Manager API to deploy. Store the Tomcat credentials securely in Jenkins:
Go to Manage Jenkins.
Click Credentials.
Click System, then Global credentials (unrestricted).
Click Add Credentials.
Fill in:
Kind: Username with password
Username:
BHATTUPassword:
BHATTUID:
tomcat-creds(or any descriptive name)Description: Tomcat Manager credentials
Click Create.
Option A: Freestyle Project with Post-Build Deployment
If you are using a Freestyle project, deployment is configured as a post-build action.
In the job configuration:
Scroll to Post-build Actions.
Click Add post-build action.
Select Deploy war/ear to a container.
Fill in:
WAR/EAR files:
**/*.war(finds any WAR file in the workspace)Context path:
my-web-app(the URL path users will use, e.g.,http://ip:8080/my-web-app)Containers: Click Add Container, select Tomcat 9.x Remote (the closest available option)
Credentials: Select
tomcat-credsTomcat URL:
http://<tomcat-ec2-public-ip>:8080
Click Save, then Build Now.
Jenkins will:
Pull the code from GitHub.
Build the WAR with Maven.
Send the WAR to Tomcat's deployment API.
Tomcat installs and starts the application.
After the build succeeds, go back to the Tomcat Manager page and refresh. You will see your application listed.
Option B: Pipeline-Based Deployment
For declarative pipelines, use the Pipeline Syntax generator to create the deployment step:
Inside your pipeline job, click Pipeline Syntax in the sidebar.
From the Sample Step dropdown, select
deploy: Deploy war/ear to a container.Fill in the same fields as above (WAR path, context path, container type, credentials, Tomcat URL).
Click Generate Pipeline Script.
Jenkins generates something like:
deploy adapters: [tomcat9(credentialsId: 'tomcat-creds',
path: '',
url: 'http://<tomcat-ip>:8080')],
contextPath: 'my-web-app',
war: '**/*.war'
Copy this and add it as a step inside a Deploy stage in your pipeline:
pipeline {
agent any
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/your-username/java-app.git'
}
}
stage('Compile') {
steps {
sh 'mvn compile'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Package') {
steps {
sh 'mvn clean package'
}
}
stage('Deploy to Tomcat') {
steps {
deploy adapters: [tomcat9(credentialsId: 'tomcat-creds',
path: '',
url: 'http://<tomcat-ip>:8080')],
contextPath: 'my-web-app',
war: '**/*.war'
}
}
}
}
Click Save, then Build Now.
Seeing the Deployed Application
After a successful build and deployment:
Open the Tomcat Manager at
http://<tomcat-ip>:8080/manager/html.You will see
my-web-applisted under Applications.Click the link or navigate directly to
http://<tomcat-ip>:8080/my-web-app.
Your Java web application is now live and served by Tomcat.
What the WAR File Path **/*.war Means
The path **/*.war uses Ant-style globbing:
**matches any directory depth (any subdirectory, including nested ones)*.warmatches any file ending in.war
Combined, **/*.war finds the WAR file no matter which subdirectory it is in. Since Maven always puts the WAR in target/, the actual WAR file being picked up is target/my-app.war (or whatever your project's artifact ID is).
Summary
The complete deployment flow now looks like this:
Developer commits code to GitHub.
Jenkins detects the commit (via webhook or Poll SCM).
Jenkins clones the repository.
Maven compiles, tests, and packages the code into a WAR file.
Jenkins uses the Deploy to Container plugin to send the WAR to Tomcat.
Tomcat deploys and starts the application.
Users access the application through the Tomcat URL.
Key points to remember:
Tomcat requires Java and a configured user in
tomcat-users.xmlwithmanager-guiandmanager-scriptroles.The IP restriction in
context.xmlmust be removed to allow Jenkins to connect remotely.The Deploy to container Plugin enables Jenkins to talk to Tomcat's deployment API.
Credentials are stored securely in Jenkins and referenced by ID in job or pipeline configuration.
The Pipeline Syntax generator creates the correct Groovy deployment code for you.
In the next posts, we will cover storing your build artifacts in AWS S3 and Nexus, and then running code quality analysis with SonarQube.






