Enable Tomcat Manager
for GitLab CI/CD
Prepare the existing Tomcat server for automated WAR deployments. Keep port 8090 and the simple build-and-deploy pipeline.
Place this lab immediately before Lab 6G. Finish with a working /manager/text/list endpoint and a deployment account that GitLab can use to upload MyWebApp.war.
Connect to the existing Tomcat server
Open the SSH session you already use for the Tomcat VM. Do not create a new VM or reinstall Java, Tomcat, or a GitLab Runner.
- Open MobaXterm.
- In the saved sessions panel, double-click the session for your Tomcat server.
- Sign in with the same SSH username and key or password used in the installation lab.
- Use this remote terminal for the Linux commands below.
Confirm the installation path
The linked installation guide uses the tomcat8 service and the /var/lib/tomcat8 directory. These commands follow that existing layout; they are not instructions to install an obsolete Tomcat release. [1]
sudo systemctl status tomcat8 --no-pager
sudo ls -l /var/lib/tomcat8/conf/tomcat-users.xmlLook for a running service and an existing configuration file. If either does not exist, use Different service name or installation path before editing anything. Do not let the editor create a new empty file in the wrong directory.
| Item | Value for the original installation |
|---|---|
| Service | tomcat8 |
| Tomcat base directory | /var/lib/tomcat8 |
| Users file | /var/lib/tomcat8/conf/tomcat-users.xml |
| Existing public address | http://YOUR-TOMCAT-PUBLIC-IP:8090 |
| Deployment account created in this lab | gitlab-deployer |
Keep port 8090 unchanged. There is no need to edit server.xml just to add a Manager user.
Find out whether Manager is already available
In the Tomcat SSH terminal, run this request without credentials:
curl --silent --output /dev/null --write-out "HTTP %{http_code}\n" \
http://localhost:8090/manager/text/list| Response | Next action |
|---|---|
401 | Usually expected: an authentication challenge. Continue with the deployment account below. |
403 | A request restriction may be active. Continue with account setup, then inspect the Manager access configuration. |
404 | Manager may be missing, stopped, or mapped to a different host. Use the recovery section below. |
000 / connection error | The local request did not get an HTTP response. Recheck the running service and port before proceeding. |
200 | Inspect the body; an unauthenticated request should not be able to administer Tomcat. Review authentication before exposing Manager. |
The ordinary Tomcat home page is not the same as the Manager application. A working home page alone does not establish that the deployment API is ready. [2]
Only for a missing Manager: follow Recover the Manager application, then repeat this step.
Generate a separate deployment password
Create a new password for GitLab rather than putting the instructor’s existing Jenkins password into a second system. Run:
openssl rand -hex 24Copy the generated value into a private password manager. You will paste it into Tomcat and later into GitLab. Do not use the placeholder shown in the next step as the real password.
Add the GitLab user to tomcat-users.xml
Back up the users file first:
sudo cp -p /var/lib/tomcat8/conf/tomcat-users.xml \
/var/lib/tomcat8/conf/tomcat-users.xml.before-gitlab-$(date +%Y%m%d-%H%M%S)Open the existing file:
sudo nano /var/lib/tomcat8/conf/tomcat-users.xml- Press Ctrl+W, type
</tomcat-users>, and press Enter. - Move to the line immediately above that closing tag.
- Paste the entries below. They must be outside any
<!-- ... -->comment. - Replace
PASTE_YOUR_GENERATED_PASSWORD_HEREwith the value from Step 4. - If
manager-scriptis already declared, keep its existing role line and add only the new user. Ifgitlab-deployeralready exists, edit that entry instead of duplicating it.
<role rolename="manager-script"/>
<user username="gitlab-deployer"
password="PASTE_YOUR_GENERATED_PASSWORD_HERE"
roles="manager-script"/>Save with Ctrl+O, press Enter to confirm the same filename, then press Ctrl+X. Do not replace the whole users file.
Restart Tomcat and test the account locally
sudo systemctl restart tomcat8
sudo systemctl status tomcat8 --no-pagerWhen Tomcat is running, test from the same SSH terminal:
curl --user gitlab-deployer \
http://localhost:8090/manager/text/listcurl prompts for the password. Paste the password you placed in tomcat-users.xml and press Enter. It is normal for password input not to appear. Specifying only the username avoids putting the password directly in the command. [8]
OK - Listed applications for virtual host [localhost]
/manager:running:0:managerLook for OK on the first line. You do not need MyWebApp to exist yet. A local failure must be resolved before testing remote access.
Test from your own computer
Leave the SSH session open. For this test, use a separate terminal on your own computer, not the Tomcat server.
- On Windows, open Start, search for PowerShell, and open it.
- Replace
YOUR-TOMCAT-PUBLIC-IPwith the same public IP or DNS name you use to open Tomcat. - Run the following command, enter the new deployment password when prompted, and inspect the response.
curl.exe --user gitlab-deployer "http://YOUR-TOMCAT-PUBLIC-IP:8090/manager/text/list"On macOS or Linux, use:
curl --user gitlab-deployer "http://YOUR-TOMCAT-PUBLIC-IP:8090/manager/text/list"Use the approved HTTPS URL instead if the instructor has already configured HTTPS. A successful local test plus a successful external test confirms two different things: the account works, and an outside client can reach it.
Do not use the browser’s Manager App button as this account’s test. That button uses /manager/html and requires a different role. Keep script credentials out of browser sessions. [2]
Resolve a localhost-only Manager restriction
Do this only when an outside request is blocked and you have confirmed which configuration is active. A localhost-only rule can explain why a local deployment works while an external client is rejected.
GitLab.com’s ordinary hosted runners do not provide a fixed outgoing IP. Your laptop’s “My IP” rule, GitLab’s web/API IPs, or one observed runner IP is not a dependable hosted-runner allowlist. [5]
A. Check the external Manager descriptor first
sudo ls -l /var/lib/tomcat8/conf/Catalina/localhost/manager.xmlIf that file exists, back it up and open it:
sudo cp -p /var/lib/tomcat8/conf/Catalina/localhost/manager.xml \
/var/lib/tomcat8/conf/Catalina/localhost/manager.xml.before-gitlab-$(date +%Y%m%d-%H%M%S)
sudo nano /var/lib/tomcat8/conf/Catalina/localhost/manager.xmlAn external manager.xml takes precedence over the Manager application’s packaged META-INF/context.xml. Preserve its existing docBase, privileged, and other settings. [3]
B. If there is no external descriptor
Check the Manager copy deployed by the original installation:
sudo ls -l /var/lib/tomcat8/webapps/manager/META-INF/context.xmlIf that file exists, back it up and edit it instead:
sudo cp -p /var/lib/tomcat8/webapps/manager/META-INF/context.xml \
/var/lib/tomcat8/webapps/manager/META-INF/context.xml.before-gitlab-$(date +%Y%m%d-%H%M%S)
sudo nano /var/lib/tomcat8/webapps/manager/META-INF/context.xmlDo not create a blank file when neither path exists. Use the actual Manager docBase or ask the instructor to locate the active configuration. Do not edit both copies blindly.
C. Change only the existing remote-address Valve
A legacy installation may contain a localhost-only block like this:
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />For the approved temporary direct-access exercise, place XML comment markers around only that block:
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->A newer installation may use RemoteCIDRValve with a localhost CIDR list instead. Apply the same comment-out approach to the existing block only; do not add another Valve or mix regex syntax with CIDR syntax. [4]
If there is no remote-address Valve in the active Manager configuration, do not invent one to remove. Another proxy, global Valve, security constraint, or authorization issue may explain the 403. Consult the troubleshooting section.
Save with Ctrl+O → Enter → Ctrl+X, then restart:
sudo systemctl restart tomcat8
sudo systemctl status tomcat8 --no-pagerRepeat the external command in Step 7. Leave web.xml authentication constraints, Realm configuration, the Host Manager application, and port 8090 unchanged.
Save the deployment details in GitLab
Use the GitLab project that runs your pipeline. These are Tomcat application credentials, not your SSH login, GitHub token, or GitLab account password.
- Open the GitLab project in your browser.
- In the project’s left sidebar, select Settings → CI/CD.
- Find Variables and select Expand if it is collapsed.
- Select Add variable. If the key already exists, select Edit instead of creating a duplicate.
- Add or update the following three entries, saving each one before adding the next.
| Key | Value | Visibility |
|---|---|---|
TOMCAT_URL | http://YOUR-TOMCAT-PUBLIC-IP:8090No trailing slash or /manager. Use HTTPS when configured. | Visible |
TOMCAT_USER | gitlab-deployer | Visible |
TOMCAT_PASSWORD | The exact generated password saved in Tomcat. | Masked and hidden for a new variable |
For each entry, use Type: Variable, Environment scope: All (*), and leave Expand variable reference off. An existing variable can be masked, but making it hidden requires creating a new variable. [6]
No APP_DIR, WAR_FILE, or TOMCAT_CONTEXT variables are needed. No changes to the two-job YAML are required.
Return to the simple build-and-deploy lab
If the pipeline file has not been created yet, continue to the beginner GitLab build-and-deploy lab. The Manager prerequisite is now configured.
If .gitlab-ci.yml already exists:
- In GitLab’s left sidebar, select Build → Pipelines.
- Select New pipeline.
- In Run for branch name or tag, select the branch containing the pipeline, usually
main. - Do not enter passwords into the manual-run form. Use the project variables saved in Step 9.
- Select New pipeline to start it.
- Open the new pipeline, then open the deploy job after the build finishes.
These are GitLab’s current manual pipeline navigation labels. [7]
In the deployment log, look for a Tomcat response starting with OK. Then open the application in your browser:
http://YOUR-TOMCAT-PUBLIC-IP:8090/MyWebApp/Close the temporary access after the exercise
- If you commented out a remote-address Valve, reopen that same file and remove the
<!--and-->markers around the original Valve. Save and restart Tomcat. - After the class no longer needs deployments, remove or disable the temporary
gitlab-deployeraccount and remove its GitLab secret. Do not remove it while students still need to finish the deployment lab. - Rotate any credentials used over public HTTP. Do not reuse the lab password for another system.
- For ongoing classes, arrange a supported Tomcat release and an HTTPS deployment endpoint with controlled access rather than repeatedly leaving Manager open.
Restoring a localhost-only Valve intentionally prevents direct deployments from GitLab-hosted runners until an approved access route is provided again.
Recovery: Manager returns 404
A 404 is a deployment or routing problem, not a reason to add more roles. First check for the two locations used by the original installation:
sudo ls -l /var/lib/tomcat8/webapps/manager/WEB-INF/web.xml
sudo ls -l /var/lib/tomcat8/conf/Catalina/localhost/manager.xml
sudo ls -l /usr/share/tomcat8-admin/manager/WEB-INF/web.xmlA missing webapps/manager directory is not conclusive if an external manager.xml points to /usr/share/tomcat8-admin/manager. Read an existing descriptor before copying files.
Restore the copied Manager only when the package source exists and neither a Manager directory nor an external Manager descriptor is active:
sudo cp -a /usr/share/tomcat8-admin/manager /var/lib/tomcat8/webapps/manager
sudo systemctl restart tomcat8Copy only manager, not every administrative application. Do not copy over an existing active Manager or install two Manager contexts.
If the package source is missing: on an existing package-managed tomcat8 installation, the following requests the admin package at the exact installed Tomcat package version:
sudo apt-get install "tomcat8-admin=$(dpkg-query -W -f='${Version}' tomcat8)"This succeeds only if that version is still available from the configured repositories. If unavailable, do not add untrusted repositories, disable signature verification, or install another Tomcat major version’s Manager. Have the instructor supply a matching distribution or move the lab to a supported release. Then repeat the location check above.
If Manager files exist but the URL still returns 404, inspect startup logs, the active virtual host, and the descriptor’s docBase instead of reinstalling blindly.
Different service name or installation path
Some students may have a newer or manually installed Tomcat even though the original article uses tomcat8. Identify the running instance; do not substitute version numbers blindly.
systemctl list-unit-files --type=service | grep -i tomcat
ps -eo pid,args | grep '[o]rg.apache.catalina.startup.Bootstrap'Find -Dcatalina.base=... in the Tomcat process arguments. Use that directory for the users file and external context descriptor:
ACTUAL_BASE/conf/tomcat-users.xml
ACTUAL_BASE/conf/Catalina/localhost/manager.xmlRestart the actual service reported by the first command. If no service is listed, the server may have been started manually or in a container; use the instructor’s existing start/stop method. Do not create a new service during this lab.
The account role and /manager/text/ URLs stay the same. The Manager application must come from the matching Tomcat version. [2] [3]
Troubleshooting by symptom
| What you see | What to check |
|---|---|
Local 401 after entering credentials | Username/password, uncommented XML, manager-script, correct running instance, and whether Tomcat was restarted. Repeated bad logins may trigger the configured lockout. |
Local OK, external 403 | Active Manager Valve, external manager.xml precedence, reverse proxy restrictions, or wider Tomcat request restrictions. |
403 at /manager/html | Expected for a script-only user. Use the terminal test at /manager/text/list; do not add GUI permissions. |
404 at /manager/text/list | Manager files, startup errors, virtual host, and docBase. Follow the recovery section. |
| Local works; external connection times out | Correct public address, port 8090, service listener, and existing firewall/security-group source rules. Opening a browser from your laptop does not prove a hosted runner is allowed. |
| Tomcat fails after editing | Restore the affected backup if necessary; inspect malformed XML, missing quotes, duplicate closing tags, or a misspelled class name. |
| GitLab authentication fails, but local tests work | Project variable values and scopes, protected-variable availability, and whether the GitLab project is the one actually running the job. |
| Job is green, app did not change | Read Tomcat’s response. With the simplified curl command, a 401, 403, or FAIL body can be missed without a manual review. |
To inspect the existing service logs:
sudo journalctl -u tomcat8 -n 100 --no-pagerIf that only shows service messages, inspect the files in /var/log/tomcat8 or the active instance’s logs directory. Do not share passwords, Authorization headers, or the complete users file when asking for help.
Completion checkpoint
- The existing Tomcat service still uses port 8090.
- The Manager text endpoint responds to the dedicated deployment account.
- Both local and external
/manager/text/listtests returnOK. - Only the three Tomcat connection variables are saved in GitLab.
- The existing two-job pipeline remains unchanged.
- Temporary exposure has an agreed cleanup step.
References
- Original DevOpStreams installation lab
- Apache Tomcat 8.5: Manager application and roles
- Apache Tomcat: Context configuration precedence
- Apache Tomcat: Remote address and CIDR valves
- GitLab.com: Runner outbound IP addresses
- GitLab: Add and protect CI/CD variables
- GitLab: Run a pipeline manually
- curl: Authentication and HTTP error handling
- Apache Tomcat: Secure management applications
- Apache Tomcat 8.0: End of support
- Apache Tomcat 8.5: End of support