In enterprise Continuous Integration and Continuous Deployment (CI/CD) pipelines, complex application lifecycles are decoupled into discrete, modular build jobs. Jenkins Chained Builds (also known as Upstream/Downstream build triggers) allow DevOps engineers to chain sequential pipeline tasks together—such as pulling latest application code, running tests, restarting web server daemons, and publishing artifacts—ensuring that downstream tasks execute strictly upon successful completion of upstream dependencies.
In this challenge, we configure a multi-job automated build chain on App Server 1 (stapp01) consisting of two Freestyle projects:
nautilus-app-deployment): Connects to the Gitea Git repository (http://gitea:3000/sarah/web.git), pulls the latest application code from the master branch, and updates the web server document root (/var/www/html).manage-services): Triggered automatically upon successful completion of nautilus-app-deployment to restart the Apache HTTP Web Server (httpd) daemon on stapp01 via systemctl restart httpd.Key tasks accomplished:
stapp01 as SSH user tony, upgrading OpenJDK from version 11 to Java 17 (java-17-openjdk), and registering stapp01 as an SSH agent node with remote root /var/www/html.nautilus-app-deployment): Creating a Freestyle project bound to node stapp01 that pulls Git updates into /var/www/html with sudo safe directory configuration.manage-services): Creating a Freestyle project bound to stapp01 that executes sudo systemctl restart httpd.nautilus-app-deployment to trigger manage-services post-build when the upstream build status is stable.nautilus-app-deployment, verifying the automated trigger of manage-services, and confirming Apache service restart and updated web application content.graph TD
subgraph UserAction ["Developer / Admin Trigger"]
Trigger["Manual Build / SCM Trigger<br/>Build Job 1"]
end
subgraph JenkinsController ["Jenkins Controller"]
Job1["Upstream Job:<br/>nautilus-app-deployment"]
ChainedTrigger["Post-Build Action:<br/>Trigger manage-services if Stable"]
Job2["Downstream Job:<br/>manage-services"]
end
subgraph AppServer ["App Server 1: stapp01"]
Java17["Java 17 Runtime<br/>java-17-openjdk"]
Agent["Jenkins Agent: tony<br/>Remote Root: /var/www/html"]
WebRoot["Apache Document Root<br/>/var/www/html"]
Httpd["Apache HTTPD Service<br/>systemctl restart httpd"]
end
Trigger -->|"1. Build Now"| Job1
Job1 -->|"2. Schedule Execution on stapp01"| Agent
Agent -->|"3. Execute Shell: git pull origin master"| WebRoot
Job1 -->|"4. Build Status: SUCCESS"| ChainedTrigger
ChainedTrigger -->|"5. Trigger Downstream Job"| Job2
Job2 -->|"6. Execute Shell: systemctl restart httpd"| Httpd
Httpd -->|"7. Serve Updated Web App"| WebRoot
Decoupling application code retrieval from service management improves pipeline maintenance:
nautilus-app-deployment) focuses exclusively on SCM code synchronization. Job 2 (manage-services) focuses exclusively on service lifecycle management.Executing Git commands and systemctl actions under non-root SSH user tony requires privilege elevation:
tony inside root-owned or shared directories like /var/www/html, Git throws fatal: detected dubious ownership in repository. Running git config --global --add safe.directory /var/www/html resolves this security check.sudo inside Jenkins shell build steps pass credentials non-interactively via echo 'password' | sudo -S <command>.8080admin / Adm!n321App Server 1 (stapp01)tony (Password: Ir0nM@n)http://gitea:3000/sarah/web.gitSSH Build Agents, Git, Publish Over SSH| Setting | Value |
|---|---|
| Node Name | App Server 1 |
| Node Label | stapp01 |
| Remote Root Directory | /var/www/html |
| Launch Method | Launch agents via SSH |
| Host | stapp01 |
| Credentials | tony (SSH Username & Password) |
| Upstream Job Name | nautilus-app-deployment |
| Upstream Build Step | echo 'Ir0nM@n' \| sudo -S git config --global --add safe.directory /var/www/htmlcd /var/www/htmlecho 'Ir0nM@n' \| sudo -S git -C /var/www/html pull origin master |
| Upstream Post-Build Action | Build other projects: manage-services |
| Downstream Job Name | manage-services |
| Downstream Build Step | echo 'Ir0nM@n' \| sudo -S systemctl restart httpd |
| Downstream Trigger | Build after other projects are built (nautilus-app-deployment) |
adminAdm!n321

stapp01 & Add Agent Nodestapp01 server as user tony from jumphost:ssh tony@stapp01
java --version
Output:
openjdk 11.0.20.1 2023-08-24 LTS
OpenJDK Runtime Environment (Red_Hat-11.0.20.1.1-2) (build 11.0.20.1+1-LTS)
yum:sudo yum install java-17-openjdk -y
java --version
Output:
openjdk 17.0.18 2026-01-20 LTS
OpenJDK Runtime Environment (Red_Hat-17.0.18.0.8-2) (build 17.0.18+8-LTS)
App Server 1/var/www/htmlstapp01stapp01tony credentials
App Server 1 status changes to In service / Online.
nautilus-app-deployment)nautilus-app-deployment and select Freestyle project.stapp01.http://gitea:3000/sarah/web.git*/master
echo 'Ir0nM@n' | sudo -S git config --global --add safe.directory /var/www/html
cd /var/www/html
echo 'Ir0nM@n' | sudo -S git -C /var/www/html pull origin master

manage-services)manage-services and select Freestyle project.stapp01.echo 'Ir0nM@n' | sudo -S systemctl restart httpd

nautilus-app-deployment.manage-services.
nautilus-app-deployment and click Build Now.
nautilus-app-deployment (Build #1):Started by user admin
Building remotely on App Server 1 (stapp01) in workspace /var/www/html
[html] $ /bin/sh -xe /tmp/jenkins123456.sh
+ echo Ir0nM@n
+ sudo -S git config --global --add safe.directory /var/www/html
+ cd /var/www/html
+ echo Ir0nM@n
+ sudo -S git -C /var/www/html pull origin master
Already up to date.
Triggering a new build of manage-services
Finished: SUCCESS
manage-services was triggered automatically and executed Build #1:Started by upstream project "nautilus-app-deployment" build number 1
originally caused by:
Started by user admin
Building remotely on App Server 1 (stapp01) in workspace /var/www/html
[html] $ /bin/sh -xe /tmp/jenkins654321.sh
+ echo Ir0nM@n
+ sudo -S systemctl restart httpd
Finished: SUCCESS

stapp01, verify Apache HTTPD service uptime and test web content:systemctl status httpd
curl http://localhost

[!TIP] If build execution fails with
sudo: a password is requiredorpermission denied, verify:
- User
tonyis configured in/etc/sudoersor/etc/sudoers.d/with passwordless sudo access or valid password injection (echo 'password' | sudo -S <cmd>).- The target web directory
/var/www/htmlallows write access to usertonyor git operations are run withsudo.
| Checkpoint | Expected Result | Status |
|---|---|---|
| Java 17 Runtime | java --version returns OpenJDK 17 on stapp01 |
PASS |
| SSH Build Agent | Node App Server 1 with label stapp01 is Online |
PASS |
| Upstream Job Setup | nautilus-app-deployment runs git pull successfully |
PASS |
| Chained Trigger Action | Post-build action configured to trigger manage-services |
PASS |
| Downstream Execution | manage-services triggers automatically on upstream success |
PASS |
| Service Lifecycle | systemctl restart httpd executes clean with status SUCCESS |
PASS |
| Application Integrity | curl http://localhost returns valid active response |
PASS |
In this challenge, we successfully established an automated Jenkins Chained Build pipeline across multiple Freestyle jobs:
stapp01 and registered the server as an SSH Build Agent using credentials for user tony.nautilus-app-deployment to pull the latest application code from Gitea into Apache’s document root /var/www/html.manage-services to restart Apache (httpd) via non-interactive sudo systemctl restart httpd.