Jenkins is the veteran open-source automation server: build, test and deploy code on every commit, run scheduled jobs, orchestrate releases. Its huge plugin ecosystem integrates with almost anything. Newer tools (GitHub Actions, GitLab CI, Woodpecker) are simpler for many teams, but Jenkins remains the go-to when you need maximum flexibility on your own infrastructure.

Requirements

  • Ubuntu 22.04/24.04 server.
  • 2 GB RAM minimum for the controller; 4 GB+ if builds run on the same machine.
  • Java (Jenkins LTS currently requires Java 17 or 21).

1. Install Java

sudo apt update
sudo apt install -y fontconfig openjdk-21-jre
java -version

2. Add the Jenkins repository and install

sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt update
sudo apt install -y jenkins
sudo systemctl enable --now jenkins

(Check jenkins.io for the current signing key URL if this one has rotated.)

Jenkins listens on port 8080. Make it listen on localhost only, so it’s reachable through Nginx:

sudo systemctl edit jenkins
[Service]
Environment="JENKINS_LISTEN_ADDRESS=127.0.0.1"
sudo systemctl daemon-reload && sudo systemctl restart jenkins

3. Nginx reverse proxy with HTTPS

server {
    listen 80;
    server_name ci.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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_http_version 1.1;
        proxy_request_buffering off;
        proxy_read_timeout 90s;
    }
}
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d ci.example.com

In Jenkins (Manage Jenkins → System), set Jenkins URL to https://ci.example.com/.

4. Unlock and set up

Get the initial admin password:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Open https://ci.example.com, paste it, choose Install suggested plugins (includes Git, Pipeline, Credentials), and create your admin user.

5. Secure Jenkins

Jenkins can run arbitrary commands on its machines — treat it as highly privileged.

  • Authorization: Manage Jenkins → Security → “Logged-in users can do anything” at minimum; better, the Matrix Authorization or Role-based Strategy plugin.
  • No builds on the controller: set the built-in node’s executors to 0 and run builds on agents. A malicious or buggy build on the controller can read all secrets.
  • Credentials: store tokens and keys in the Credentials store; reference them in pipelines rather than hard-coding.
  • Keep Jenkins and plugins updated — plugin vulnerabilities are common. Remove unused plugins.
  • Restrict access with a VPN or IP allow-list if only your team uses it.

6. Your first pipeline

Create a Pipeline job (or Multibranch Pipeline for all branches) pointing to your Git repository. Add a Jenkinsfile to the repo:

pipeline {
    agent any
    stages {
        stage('Install') {
            steps { sh 'npm ci' }
        }
        stage('Test') {
            steps { sh 'npm test' }
        }
        stage('Deploy') {
            when { branch 'main' }
            steps {
                sshagent(credentials: ['deploy-key']) {
                    sh 'rsync -az --delete dist/ [email protected]:/var/www/app/'
                }
            }
        }
    }
    post {
        failure { echo 'Build failed' }
    }
}

The sshagent step needs the SSH Agent plugin and an SSH key stored as a Jenkins credential with ID deploy-key.

Trigger builds from Git pushes with a webhook (GitHub/GitLab/Gitea plugin) instead of polling.

7. Agents

Run builds on separate machines:

  • SSH agents: Manage Jenkins → Nodes → New Node → launch via SSH to another VPS with Java installed.
  • Docker agents: agent { docker { image 'node:22' } } in a Jenkinsfile runs each build in a fresh container (needs Docker on the agent and the Docker Pipeline plugin).
  • Kubernetes agents: the Kubernetes plugin starts build pods on demand.

8. Backups

Everything lives in JENKINS_HOME (/var/lib/jenkins): jobs, configs, credentials (encrypted with keys in secrets/), plugins. Back up the whole directory, excluding workspace/ and caches:

sudo tar czf jenkins-$(date +%F).tar.gz --exclude='workspace' --exclude='caches' -C /var/lib jenkins

Configuration-as-Code (the JCasC plugin) lets you keep Jenkins configuration in YAML in Git.

9. Updates

sudo apt update && sudo apt install --only-upgrade jenkins

Update plugins from Manage Jenkins → Plugins. Back up first.

Alternatives

If your code lives on GitHub, GitHub Actions deploying to a VPS may be simpler. Self-hosted alternatives: Woodpecker CI, Gitea Actions, GitLab CI. See CI/CD pipelines explained.

Run the Jenkins controller and build agents on separate KVM VPS servers — builds stay isolated and the controller stays responsive.

  • Jenkins
  • CI/CD
  • DevOps