How to Install Jenkins on Ubuntu 24.04 — Self-Hosted CI/CD Server
Jenkins is the most widely deployed automation server on the planet, powering continuous integration and delivery pipelines at companies ranging from two-person startups to Fortune 50 enterprises. This guide walks through a production-ready Jenkins installation on Ubuntu 24.04, from the first apt update to a fully configured controller-agent architecture sitting behind an Nginx TLS reverse proxy, building your code on every push to GitHub.
Need a VPS first? The CloudCore Professional plan (EUR 19.99/month) provides the 4 GB of RAM and multi-core CPU that a Jenkins controller plus one or two inline agents will use comfortably.
Table of Contents
What is Jenkins?
Jenkins is an open-source automation server, originally released in 2011 as a fork of the Hudson project, and maintained today by the Continuous Delivery Foundation. It orchestrates the repetitive work that sits between a developer pressing git push and a production server receiving new code: compiling, testing, packaging, scanning, deploying, and notifying.
Out of the box Jenkins is a single Java process that exposes a web UI, an HTTP API, and a remoting protocol for distributed builds. Its real power comes from the plugin ecosystem — over 1,800 community plugins cover everything from Git and GitHub integration to Docker, Kubernetes, Slack notifications, SonarQube analysis, Artifactory publishing, and dozens of cloud providers. Pipelines are defined as code via the Jenkinsfile, a Groovy-based DSL that lives alongside your application source.
Jenkins shines when builds are heavy, parallelisable, and cost-sensitive. A single controller can dispatch work to dozens of ephemeral agents, run long integration suites against real databases, or compile cross-platform artifacts without burning through a per-minute billing meter. See the official documentation at jenkins.io/doc for the full reference.
Why Self-Host Jenkins vs. GitHub Actions or CircleCI?
Managed CI services are tempting for small projects — the free tiers are generous, setup is trivial, and there is no server to maintain. Once your team or your test suite grows, the economics flip.
- Cost at scale. GitHub Actions bills USD 0.008 per minute on Linux once the 2,000–3,000 free minutes per month are exhausted. A single repo running a 15-minute pipeline on every push from a team of ten can burn through 30,000 minutes a month, which is roughly USD 240. CircleCI's performance plans start at USD 15 per user plus usage credits, and Buildkite charges per agent. A CloudCore Professional VPS at EUR 19.99/month gives you unlimited build minutes, as many parallel jobs as your CPU supports, and no surprise overage bills.
- Hardware control. On managed runners you pick from a short menu of preset machines. On your own VPS you can pin builds to NVMe storage, mount local Docker layer caches, tune kernel parameters, or attach GPU accelerators for ML pipelines.
- Private network access. Self-hosted Jenkins sits inside your own network perimeter, so it can reach internal databases, staging environments, and private package registries without firewall gymnastics or expensive "runner inside VPC" add-ons.
- No vendor lock-in. A
Jenkinsfileis portable. GitHub Actions workflows, CircleCI configs, and Buildkite pipelines all use proprietary YAML formats, so migrating later means rewriting every job. - Data residency and compliance. For EU teams handling regulated data, keeping CI artifacts on a known EU-hosted VPS simplifies GDPR and sector-specific audits.
- Deep customization. Jenkins plugins can extend the UI, add new DSL steps, integrate with internal systems, and hook into every lifecycle event. Managed services expose a fraction of this surface.
Rough Cost Comparison at 30,000 Build Minutes / Month
| Platform | Monthly Cost | Parallelism | Caveats |
|---|---|---|---|
| GitHub Actions (hosted) | ~USD 216 (overage) | 20 concurrent | Linux only at this price; macOS/Windows 10x cost |
| CircleCI Performance | ~USD 150+ | 30 concurrent | Credit-based, easy to overrun |
| Buildkite (hosted agents) | ~USD 200+ | Agent-based | Pay per agent-minute |
| Self-hosted Jenkins (CloudCore Professional) | EUR 19.99 | Limited by CPU/RAM | You own uptime and patches |
Prerequisites
Before you begin, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to your server
- At least 4 GB of RAM for the controller (8 GB+ recommended if you intend to run inline builds)
- At least 20 GB of free disk space (Jenkins data grows with build history and artifacts)
- A domain name pointing to your server's public IP, for TLS later on
Recommended Plan: CloudCore Professional>
Our CloudCore Professional plan is the sweet spot for a Jenkins controller plus one or two inline build executors:>
- 6 vCPU cores
- 12 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth
- EUR 19.99/month>
For teams running heavier test matrices, add a second VPS as a dedicated build agent — Jenkins handles distributed agents natively.
Connect to the server to get started:
ssh root@your-server-ipStep 1: Update System Packages
Refresh the apt package index and apply any pending updates. This ensures the kernel, OpenSSL, and system libraries are current before Jenkins pulls in its Java runtime.
sudo apt update && sudo apt upgrade -yIf the kernel was upgraded, reboot:
sudo rebootReconnect after a minute and continue.
Step 2: Install OpenJDK 17
Jenkins 2.426 and later require Java 17 or Java 21. Ubuntu 24.04 ships OpenJDK 17 directly from the default repositories, so no third-party PPA is needed.
Install the headless JRE (no GUI libraries, much smaller footprint):
sudo apt install -y openjdk-17-jre-headlessVerify the installation:
java -versionExpected output:
openjdk version "17.0.13" 2025-10-15
OpenJDK Runtime Environment (build 17.0.13+11-Ubuntu-2ubuntu124.04)
OpenJDK 64-Bit Server VM (build 17.0.13+11-Ubuntu-2ubuntu124.04, mixed mode, sharing)If you plan to build Java applications on this same server, install the full JDK instead:
sudo apt install -y openjdk-17-jdk-headlessStep 3: Add the Jenkins LTS apt Repository
The LTS (Long Term Support) release line is the right choice for production — it receives security fixes for 12 weeks at a time and is the version the plugin ecosystem targets first.
Import the Jenkins signing key:
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2023.keyAdd the apt source:
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/" | \
sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/nullRefresh the package index so apt sees the new repo:
sudo apt updateStep 4: Install and Start Jenkins
Install the jenkins package:
sudo apt install -y jenkinsThe package creates a dedicated jenkins system user, installs the main WAR into /usr/share/java/jenkins.war, and drops a systemd unit at /lib/systemd/system/jenkins.service. The service starts automatically.
Verify the service is running:
sudo systemctl status jenkinsExpected output:
● jenkins.service - Jenkins Continuous Integration Server
Loaded: loaded (/lib/systemd/system/jenkins.service; enabled; preset: enabled)
Active: active (running) since Thu 2026-04-16 09:12:03 UTC; 10s ago
Main PID: 4821 (java)
Tasks: 41 (limit: 14236)
Memory: 512.3M
CPU: 18.412sJenkins listens on TCP port 8080 by default. Open it in your firewall if UFW is enabled:
sudo ufw allow 8080/tcp
sudo ufw allow OpenSSH
sudo ufw --force enableIf you plan to attach inbound agents via JNLP, also open the agent port (by default random; you will fix it in Step 8):
sudo ufw allow 50000/tcpStep 5: Unlock Jenkins and Run the Setup Wizard
Browse to http://your-server-ip:8080. On first access Jenkins displays an Unlock Jenkins screen asking for the initial admin password.
Read the password from disk:
sudo cat /var/lib/jenkins/secrets/initialAdminPasswordExpected output:
7f3d1a2b4c5e6f7a8b9c0d1e2f3a4b5cPaste this value into the web form and click Continue. The password is a one-time unlock token and can be discarded afterwards.
Step 6: Install Recommended Plugins and Create an Admin User
On the next screen Jenkins asks whether to install suggested plugins or pick plugins manually. Click Install suggested plugins. This batch installs roughly 20 plugins covering the common ground:
- Git, GitHub Branch Source, Pipeline, Pipeline: Stage View
- Credentials Binding, SSH Build Agents
- Timestamper, Workspace Cleanup, Build Timeout
- Email Extension, Mailer
- Matrix Authorization Strategy, LDAP
updates.jenkins.io are common.Once plugins finish, the Create First Admin User form appears. Fill in a real username (not admin), a strong password, your full name, and an email. Click Save and Continue.
On the Instance Configuration page, set the Jenkins URL to the public address you will use, for example https://jenkins.example.com/. This URL is baked into webhook callbacks, email links, and agent JNLP files — changing it later requires updating each integration, so get it right now.
Click Save and Finish, then Start using Jenkins.
Step 7: Configure Global Security
The defaults are sane, but a handful of tweaks harden a public-facing Jenkins significantly. Navigate to Manage Jenkins → Security.
Overall/Administer permission. For every other user, grant only Overall/Read plus the job-level permissions they need. Do not grant anonymous any permission.50000 so firewall rules are stable.Click Save. Then visit Manage Jenkins → System and confirm the Jenkins URL matches your public hostname.
Step 8: Controller-Agent Architecture
A single-node Jenkins (controller runs builds on itself) works for a hobby project, but for anything serious you want a controller-agent split: the controller schedules jobs and serves the UI, and agents run the actual builds. This isolates untrusted build code from the controller filesystem and lets you scale horizontally.
SSH Build Agents
The simplest agent type is an SSH agent — any Linux machine reachable via SSH can be pressed into service.
On the agent machine:
sudo adduser --disabled-password --gecos "" jenkins
sudo mkdir -p /home/jenkins/.ssh
sudo chown jenkins:jenkins /home/jenkins/.ssh
sudo chmod 700 /home/jenkins/.ssh
sudo apt install -y openjdk-17-jre-headless gitOn the controller, generate an SSH keypair for Jenkins:
sudo -u jenkins ssh-keygen -t ed25519 -N "" -f /var/lib/jenkins/.ssh/id_ed25519
sudo cat /var/lib/jenkins/.ssh/id_ed25519.pubCopy the public key into /home/jenkins/.ssh/authorized_keys on the agent. In the Jenkins UI, go to Manage Jenkins → Nodes → New Node, give it a name (e.g. agent-linux-01), choose Permanent Agent, and configure:
- Remote root directory:
/home/jenkins/agent - Labels:
linux docker(used by pipelines to target this agent) - Launch method: Launch agents via SSH
- Host: the agent's IP
- Credentials: add a new "SSH Username with private key" credential using the private key from
/var/lib/jenkins/.ssh/id_ed25519 - Host Key Verification Strategy: Known hosts file
Docker Agents
For disposable, clean-room builds, the Docker Pipeline and Docker plugins let Jenkins spin up a container per pipeline run. Install Docker on the agent (or on the controller if you accept the security trade-off):
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker jenkinsConfigure a Docker cloud under Manage Jenkins → Clouds → New cloud → Docker, pointing at unix:///var/run/docker.sock (local) or a remote tcp:// endpoint. Define templates such as jenkins/inbound-agent:latest with labels docker linux, and Jenkins will start a container on demand when a pipeline requests that label.
This pattern — ephemeral Docker agents on each build — is the gold standard for reproducibility and is covered in depth in our Docker install guide.
Step 9: Write Your First Declarative Pipeline
Jenkins pipelines come in two flavors: scripted (pure Groovy) and declarative (structured DSL). Declarative is strongly recommended — it is easier to read, validates at parse time, and plays well with Blue Ocean.
Create a new item from the dashboard, select Pipeline, name it hello-pipeline, and paste the following into the Pipeline script field:
pipeline { agent { label 'linux' }options { timeout(time: 10, unit: 'MINUTES') buildDiscarder(logRotator(numToKeepStr: '20')) timestamps() }
environment { APP_NAME = 'demo-service' }
stages { stage('Checkout') { steps { git url: 'https://github.com/jenkinsci/pipeline-examples.git', branch: 'master' } }
stage('Build') { steps { sh 'echo "Building ${APP_NAME} on $(hostname)"' sh 'uname -a' } }
stage('Test') { parallel { stage('Unit') { steps { sh 'echo "running unit tests"' } } stage('Lint') { steps { sh 'echo "running lint"' } } } }
stage('Deploy') { when { branch 'main' } steps { sh 'echo "deploying ${APP_NAME}"' } } }
post { success { echo 'Build succeeded' } failure { echo 'Build failed — check the console log' } always { cleanWs() } } }
Click Save, then Build Now. The Stage View shows each stage as a column, with green or red indicators per run. Declarative pipelines cover when conditions, parallel stages, matrix builds, shared libraries, and timeouts out of the box.
The recommended workflow is to commit this pipeline as a Jenkinsfile at the root of the application repo — then Jenkins executes whatever pipeline is on the branch it is building, and pipeline changes go through code review just like application changes.
Step 10: Multibranch Pipelines and GitHub Webhooks
A Multibranch Pipeline scans a Git repository and automatically creates a Jenkins job for every branch and pull request that contains a Jenkinsfile. Combined with a GitHub webhook, this gives you on-push CI without any per-branch configuration.
Create a new item, select Multibranch Pipeline, name it after your repo, and configure:
- Branch Sources → GitHub
- Credentials: a GitHub personal access token with
reposcope (add it via the Credentials store — see Step 11) - Repository HTTPS URL:
https://github.com/your-org/your-repo - Behaviours: Discover branches, Discover pull requests from origin, Discover pull requests from forks
- Build Configuration → Mode: by Jenkinsfile (default path)
Configuring the GitHub Webhook
Jenkins polls GitHub every few minutes by default, but webhooks are much faster. On the GitHub repo, go to Settings → Webhooks → Add webhook:
- Payload URL:
https://jenkins.example.com/github-webhook/ - Content type:
application/json - Events: Let me select — pick Pushes, Pull requests, and Branch or tag creation
If you prefer self-hosted Git forges, the same flow works with our Gitea install guide — the Git plugin treats any Git remote identically.
Step 11: The Credentials Store
Hard-coding passwords in Jenkinsfiles is a cardinal sin. Jenkins ships with an encrypted Credentials store that plugins can pull from at build time.
Navigate to Manage Jenkins → Credentials → System → Global credentials (unrestricted) → Add Credentials. Common kinds:
- Username with password — for basic-auth APIs and Docker registries
- SSH Username with private key — for deploying to remote hosts
- Secret text — for API tokens (GitHub, Slack, AWS session tokens)
- Secret file — for service-account JSONs and kubeconfig files
- Certificate — for TLS client auth
github-pat, aws-prod-deploy). Consume them in pipelines with the credentials() helper or the withCredentials block:pipeline {
agent { label 'linux' }
environment {
GITHUB_TOKEN = credentials('github-pat')
}
stages {
stage('Push tag') {
steps {
withCredentials([sshUserPrivateKey(
credentialsId: 'deploy-key',
keyFileVariable: 'DEPLOY_KEY')]) {
sh 'ssh -i $DEPLOY_KEY deploy@prod "touch /tmp/deployed"'
}
}
}
}
}Secrets are masked in build console logs automatically — never echo them to stdout anyway.
For even stronger hygiene, integrate HashiCorp Vault via the HashiCorp Vault Plugin and let Jenkins fetch short-lived dynamic secrets per build.
Step 12: Blue Ocean for a Modern UI
The classic Jenkins UI is functional but dated. Blue Ocean is an alternative frontend with a cleaner pipeline visualization, better PR-centric views, and a pipeline editor.
Install via Manage Jenkins → Plugins → Available plugins, search Blue Ocean, select it, and install without restart. A new Open Blue Ocean link appears in the left sidebar.
Blue Ocean shines on multibranch pipelines — each branch gets a dedicated card, each run shows a timeline with per-stage logs, and PRs have a comment-style build status. It is a nice productivity boost for developers who live in the Jenkins UI day to day, though the classic UI remains the source of truth for administration.
Step 13: Nginx Reverse Proxy with Let's Encrypt TLS
Never expose port 8080 directly on the public internet. Terminate TLS on Nginx in front of Jenkins, and keep port 8080 bound to localhost.
First, tell Jenkins to listen only on localhost. On systemd-based installs, create an override:
sudo systemctl edit jenkinsAdd:
[Service]
Environment="JENKINS_LISTEN_ADDRESS=127.0.0.1"Reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart jenkinsInstall Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxCreate the site config:
sudo tee /etc/nginx/sites-available/jenkins > /dev/null <<'EOF' upstream jenkins { server 127.0.0.1:8080 fail_timeout=0; keepalive 32; }server { listen 80; server_name jenkins.example.com; return 301 https://$host$request_uri; }
server { listen 443 ssl http2; server_name jenkins.example.com;
ssl_certificate /etc/letsencrypt/live/jenkins.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/jenkins.example.com/privkey.pem;
# Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options SAMEORIGIN;
# Jenkins needs a generous body size for plugin uploads and artifacts client_max_body_size 100m; client_body_buffer_size 128k;
location / { proxy_pass http://jenkins; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Connection "";
proxy_redirect http://jenkins/ https://$host/;
# Required for long-running builds and SSE in Blue Ocean proxy_buffering off; proxy_request_buffering off; proxy_read_timeout 900s; proxy_send_timeout 900s; } } EOF
Replace jenkins.example.com with your domain. Enable the site and obtain a certificate:
sudo ln -s /etc/nginx/sites-available/jenkins /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d jenkins.example.comCertbot edits the config to point at the new certificate and installs a renewal timer. Reload Nginx:
sudo systemctl reload nginxClose port 8080 on the firewall now that Jenkins is only reachable via Nginx:
sudo ufw delete allow 8080/tcp
sudo ufw allow 'Nginx Full'Finally, update the Jenkins URL under Manage Jenkins → System to https://jenkins.example.com/ so webhooks and email links use the TLS endpoint.
Step 14: Back Up Jenkins with ThinBackup
Jenkins state lives in /var/lib/jenkins (a.k.a. JENKINS_HOME) — configuration, job definitions, plugins, build history, and credentials. Without a backup strategy one bad plugin upgrade can ruin your day.
Install the ThinBackup plugin via Manage Jenkins → Plugins → Available plugins. After restart, a new ThinBackup entry appears under Manage Jenkins.
Configure it with:
- Backup directory:
/var/lib/jenkins-backups(create this directory owned byjenkins:jenkins) - Full backup schedule:
H 2 0(Sunday at ~2 am) - Differential backup schedule:
H 2 1-6(every other night) - Max number of backup sets:
10 - Files excluded from backup:
.*\.log(skip verbose logs) - Check: Backup build results, Backup configuration history, Clean up differential backups
sudo mkdir -p /var/lib/jenkins-backups
sudo chown jenkins:jenkins /var/lib/jenkins-backupsTrigger a backup immediately to verify everything works — click Backup Now on the ThinBackup page.
Offsite Copies with restic
ThinBackup keeps you safe from configuration mistakes but not from disk loss. Layer an offsite copy on top:
sudo apt install -y restic
sudo restic -r s3:s3.amazonaws.com/your-bucket/jenkins init
sudo restic -r s3:s3.amazonaws.com/your-bucket/jenkins backup /var/lib/jenkins-backupsSchedule it via cron:
sudo crontab -eAppend:
30 3 * restic -r s3:s3.amazonaws.com/your-bucket/jenkins backup /var/lib/jenkins-backups --password-file /root/.restic-passwordNow your Jenkins survives both human error and hardware failure.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
jenkins.service: Failed with result 'exit-code' on startup | Wrong Java version | Confirm java -version shows 17 or 21. Reinstall with sudo apt install --reinstall openjdk-17-jre-headless |
| Setup wizard hangs on "Getting started" | Plugins failing to download | Retry, or visit Manage Jenkins → Update Sites and confirm the URL is reachable. Check DNS and outbound HTTPS. |
Nginx 502 Bad Gateway after moving behind proxy | Jenkins not listening on 127.0.0.1 | Check ss -tlnp — Jenkins should be on 127.0.0.1:8080. Verify systemd override and restart Jenkins. |
| Builds queue forever, never run | No executor available | Check Manage Jenkins → Nodes. Controller may have 0 executors set (correct for controller-agent). Connect an agent or raise controller executors. |
| GitHub webhook returns 403 | CSRF crumb required | Upgrade GitHub plugin to latest — old versions did not send the crumb. Or switch to HMAC secret validation. |
No space left on device after a few weeks | Build history + artifacts | Add a buildDiscarder to every pipeline (numToKeepStr: '20'), or use the Discard Old Builds job option. |
| Agent disconnects intermittently | Firewall closing idle connections | On the agent, add -keepAlive to the JNLP launch command, or switch the agent to SSH launcher which tunnels over a persistent TCP session. |
javax.net.ssl.SSLHandshakeException on outbound calls | Corporate proxy with custom CA | Import the CA into $JAVA_HOME/lib/security/cacerts with keytool -importcert, then restart Jenkins. |
Useful Log Locations
# Main Jenkins log
sudo journalctl -u jenkins -fOlder package layout
sudo tail -f /var/log/jenkins/jenkins.logPer-job workspace and build logs
ls /var/lib/jenkins/jobs/<job-name>/builds/FAQ
Which Java version does Jenkins require on Ubuntu 24.04?
Jenkins 2.426 and later require Java 17 or Java 21. Ubuntu 24.04 ships OpenJDK 17 directly, which is the cleanest option — no PPA, no third-party repository, and fully supported by the Jenkins LTS line. Do not attempt to run Jenkins on Java 11 anymore; newer plugins use Java 17 bytecode and will throw UnsupportedClassVersionError.
Should I self-host Jenkins or use GitHub Actions?
Self-hosted Jenkins wins on cost once your monthly CI minutes exceed roughly 2,000–3,000 (the GitHub free tier). A EUR 19.99 VPS gives you unlimited build minutes versus USD 0.008 per minute overage on GitHub Actions. Jenkins also wins on hardware control, private network access, and deep customization. GitHub Actions wins on zero-maintenance simplicity. A common hybrid is to run lightweight PR checks on GitHub Actions and heavy nightly suites, integration tests, and release pipelines on self-hosted Jenkins.
How do I scale Jenkins beyond a single VPS?
Add build agents. The Jenkins controller stays lightweight — it schedules jobs and stores artifacts — while agents run on separate machines. Agent types include SSH (any Linux host), JNLP/inbound (firewall-friendly), Docker (ephemeral containers per build), and Kubernetes (pods per build). Start with one SSH agent on a second VPS, then add Docker templates as your test matrix grows. The Jenkins Kubernetes plugin is the endgame for elastic, autoscaling CI.
Is Jenkins secure to expose on the public internet?
Yes, with standard hardening: front with Nginx + TLS (Step 13), bind Jenkins to localhost, enable matrix-based authorization with no anonymous permissions, disable CLI-over-remoting, use the Credentials store for secrets, keep the controller Java process away from builds (use agents), and patch the LTS release promptly when CVEs are announced. Jenkins publishes a security advisory mailing list — subscribe at jenkins.io/security.
How do I back up Jenkins configuration and jobs?
Install the ThinBackup plugin for scheduled full and differential backups of JENKINS_HOME, then layer an offsite copy with restic, borg, or rsync. Exclude the workspace/ directories (re-creatable from source) and large build artifacts (store in a dedicated artifact server like Nexus or Artifactory). Test the restore procedure quarterly — an untested backup is not a backup.
What is a Jenkinsfile and why should I use one?
A Jenkinsfile is a text file at the root of your repository that defines the entire pipeline using the declarative (or scripted) DSL. Storing it in Git means pipeline changes go through the same code review, testing, and rollback workflow as application code. Different branches can have different pipelines (a hotfix branch might skip integration tests), and bisecting a pipeline bug is as easy as git log. Inline pipelines configured through the UI lose all of this.
Can I run Jenkins builds inside Docker containers?
Yes, and you should whenever practical. The Docker Pipeline plugin lets any stage declare agent { docker { image 'node:20' } }, and Jenkins runs the stage inside a fresh container. This gives each build a clean, reproducible environment without polluting the host with toolchains. Pair with Docker Cloud configuration to spin up throwaway inbound agents on demand. Teams running many parallel builds often move to our Drone CI guide or Woodpecker CI guide for container-first workflows, while keeping Jenkins for legacy and Java-heavy pipelines.
Next Steps
- Explore alternative CI systems. Every self-hosted CI has trade-offs. Our guides on Drone CI, Woodpecker CI, and Concourse compare alternatives that are container-first and YAML-native.
- Pair Jenkins with self-hosted Git. Installing Gitea gives you a GitHub-style frontend on your own VPS; Jenkins multibranch scans it exactly like GitHub.
- Standardize build environments with Docker. Follow the Docker install guide on your Jenkins agents so pipelines can use
agent { docker { image '...' } }freely. - Wire up notifications. Install the Slack, Microsoft Teams, or Discord plugin and
post { failure { slackSend ... } }in your pipelines so failures surface where your team already lives. - Add static analysis and security scanning. SonarQube, Trivy (container CVEs), and OWASP Dependency-Check plugins integrate as pipeline stages and fail builds on new vulnerabilities.
- Migrate to configuration-as-code. The JCasC (Configuration as Code) plugin encodes your entire Jenkins configuration into a YAML file, so a fresh install is a
helm installordocker runaway. Combined with a restoredJENKINS_HOME, it makes disaster recovery nearly automatic.
Running Jenkins on a VPS that can handle it>
Jenkins controllers are memory-hungry, and build executors compound that. The CloudCore Professional plan gives you 6 vCPU, 12 GB RAM, and 100 GB NVMe for EUR 19.99/month — enough for a controller, two inline executors, and headroom for a dozen concurrent pipeline branches.>
- Ubuntu 24.04 LTS image with SSH key pre-installed
- 1 Gbps unmetered bandwidth for pulling container images
- NVMe storage for fast workspace checkouts
- Snapshot-based backups for easy rollback>
Deploy a Jenkins-ready VPS and be building code in under 40 minutes.