Deploy Apache Tomcat Using Ansible

If you’re planning to set up multiple Apache Tomcat instances, Ansible is an excellent automation tool to consider.
Ansible works over SSH and doesn’t require any agents on the managed nodes. It’s lightweight, with no need to install a database or run background daemons.
By writing a simple Ansible playbook, you can automate the deployment of multiple Tomcat servers efficiently and consistently.
In this guide, we’ll walk you through the process of installing Apache Tomcat using Ansible.
Prerequisites
- A control node with Ansible installed
- One or more target nodes (Ubuntu)
- SSH access from control to target node (using SSH keys)
- Sudo access on the target nodes
- Internet access on the target nodes
Create folder
$ mkdir ansible-tomcat
$ cd ansible-tomcat
Step 1: Create the Inventory File
What is an Inventory File?
An Ansible inventory file is where you list the IP addresses or hostnames of the machines (called managed nodes or target servers) that Ansible will control.
It also defines groups of servers for easy management and task execution.
File Name
Typically named something like inventory.ini
, but you can name it anything. It’s a plain text file.
$ nano inventory.ini

Save with Ctrl + O
, press Enter
, and then exit with Ctrl + X
.
Step 2: Create the Ansible Playbook
Create a file named t
omcat_deploy.yml
:
$ nano tomcat_deploy.yaml
- name: Install and configure Apache Tomcat on all servers
hosts: tomcat_servers
become: yes
vars:
tomcat_version: 9.0.89
tomcat_user: tomcat
install_dir: /opt/tomcat
tasks:
- name: Install Java (required for Tomcat)
apt:
name: default-jdk
state: present
- name: Create Tomcat user
user:
name: "{{ tomcat_user }}"
shell: /bin/false
- name: Download Tomcat archive
get_url:
url: "https://downloads.apache.org/tomcat/tomcat-9/v{{ tomcat_version }}/bin/apache-tomcat-{{ tomcat_version }}>
dest: /tmp/tomcat.tar.gz
- name: Create Tomcat installation directory
file:
path: "{{ install_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Extract Tomcat
unarchive:
src: /tmp/tomcat.tar.gz
dest: "{{ install_dir }}"
remote_src: yes
creates: "{{ install_dir }}/apache-tomcat-{{ tomcat_version }}"
- name: Change ownership
file:
path: "{{ install_dir }}/apache-tomcat-{{ tomcat_version }}"
owner: "{{ tomcat_user }}"
group: "{{ tomcat_user }}"
recurse: yes
- name: Create symlink for easier access
file:
src: "{{ install_dir }}/apache-tomcat-{{ tomcat_version }}"
dest: "{{ install_dir }}/latest"
state: link
- name: Setup systemd service for Tomcat
copy:
dest: /etc/systemd/system/tomcat.service
content: |
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target
[Service]
Type=forking
User={{ tomcat_user }}
Group={{ tomcat_user }}
Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
Environment=CATALINA_PID={{ install_dir }}/latest/temp/tomcat.pid
Environment=CATALINA_HOME={{ install_dir }}/latest
Environment=CATALINA_BASE={{ install_dir }}/latest
ExecStart={{ install_dir }}/latest/bin/startup.sh
ExecStop={{ install_dir }}/latest/bin/shutdown.sh
Restart=on-failure
[Install]
WantedBy=multi-user.target
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Start and enable Tomcat service
systemd:
name: tomcat
state: started
enabled: yes

Step 3: Run the Playbook
$ ansible-playbook -i inventory.ini tomcat_deploy.yml –ask-become-pass
As you can see below, all the tasks are successfully completed; if the status of TASK shows ok, that means the task was already completed; else, for changed status, Ansible performs the task on the remote node.


Next, verify remote machine if Apache Tomcat is installed successfully and started use the below command.
$ systemctl status tomcat
$ service tomcat status

Restart the Tomcat service
$ sudo systemctl restart tomcat
Recheck if Tomcat is now listening on port 8081
$ sudo lsof -i :8081
Step 4: Verify Tomcat Installation
- Open your browser and visit:
http://<target-server-ip>:808
1
You should see the Apache Tomcat welcome page.

- Jenkins Monitoring with Prometheus and Grafana - July 21, 2025
- Cursor AI: Why use Cursor AI? - July 9, 2025
- Grafana Setup - June 30, 2025