Post

Setting up Jenkins on Proxmox in a home lab

Comprehensive guide to deploying Jenkins on Proxmox in a home lab, featuring multi-agent setup with Linux and macOS, Docker integration, secure SSH configuration, and best practices for scalable, cross-platform CI/CD automation.

Setting up Jenkins on Proxmox in a home lab

Jenkins is a powerful automation server used to build, test, and deploy software. In many setups, the Jenkins master orchestrates builds, but doesn’t perform them directly-builds run on agents or slaves. This article walks through how to deploy Jenkins in a Proxmox‑based home lab with a reverse proxy, where the master delegates all builds to two slaves: one Linux LXC (Docker‑capable), and one macOS SSH slave.


🚀 Prerequisites

  • A Proxmox VE hypervisor running Debian‑based host.
  • Nginx Proxy Manager (or equivalent) configured to expose the Jenkins master via HTTPS.
  • Basic familiarity with Proxmox, LXC containers, macOS terminal, SSH.
  • SSH keypair for connecting master → slaves.
  • Docker installed on the LXC slave.

🎯 Overview of the Architecture

  • Jenkins master runs in a lightweight container (LXC) or Docker, but only handles coordination, plugins, user interface, and job scheduling.
  • Slave #1: Linux LXC container, Docker installed → used for Docker‑based builds, pipelines, container testing.
  • Slave #2: A macOS host (could be a Mac Mini or a VM) configured as an SSH agent to run macOS‑specific jobs (e.g. iOS builds, multi‑platform tools).
  • Reverse proxy (Nginx Proxy Manager) handles public access and TLS termination for the Jenkins master UI.

⚙️ Setting Up Jenkins Master (LXC or Docker)

  1. Create an LXC container in Proxmox (Debian/Ubuntu preferred).
  2. Install Java (OpenJDK 17 or 21 as supported):

    1
    
    apt update && apt install -y openjdk-17-jdk-headless
    
  3. Install Jenkins (generic War or apt repo):

    1
    2
    3
    
    wget -qO - https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add -  
    add-apt-repository "deb https://pkg.jenkins.io/debian-stable binary/"  
    apt update && apt install -y jenkins
    
  4. Configure Jenkins to run with no built‑in executors:

    • Navigate to Manage Jenkins → Configure System.
    • Set # of executors to 0.
  5. Open ports if necessary inside the LXC: ensure port 8080 is reachable by the proxy only.
  6. Point Nginx Proxy Manager (or your reverse proxy) to this LXC’s internal IP and port 8080. Set up TLS, basic auth, and routing.

🔧 Configuring Jenkins Slave #1 (Linux LXC + Docker)

  1. Provision a new LXC container, e.g. Ubuntu.
  2. Install Docker:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    apt-get update
    apt-get install ca-certificates curl
    install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    chmod a+r /etc/apt/keyrings/docker.asc
    
    # Add the repository to Apt sources:
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
      tee /etc/apt/sources.list.d/docker.list > /dev/null
    apt-get update
    
    apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
  3. Add user (e.g. jenkins) to Docker group:

    1
    2
    
    useradd -m -s /bin/bash jenkins  
    usermod -aG docker jenkins
    
  4. Enable SSH and add the Jenkins master’s public key to ~jenkins/.ssh/authorized_keys.
  5. In the Jenkins master UI, go to Manage Nodes & Clouds → New Node → configure:

    • Launch via SSH
    • Host: LXC’s IP
    • Credentials: private key of the master
    • Remote FS root: /home/jenkins
  6. Confirm that the agent connects successfully.
  7. Now in pipelines or jobs, you can configure to run on this label and leverage Docker builds:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    pipeline {
      agent { label 'docker-agent' }
      stages {
        stage('Build') {
          steps {
            sh 'docker build -t myapp:latest .'
          }
        }
      }
    }
    

🍎 Configuring Jenkins Slave #2 (macOS via SSH)

  1. On the macOS machine, enable Remote Login (System Preferences → Sharing → Remote Login).
  2. Create a Jenkins user or choose a dedicated user, and install Homebrew, Xcode tools, etc.
  3. Add the master’s SSH public key to ~jenkins/.ssh/authorized_keys.
  4. Ensure required tools are installed (Java agent jar, Xcode Command Line Tools, etc.).
  5. On the Jenkins master UI, add a new node:

    • Launch via SSH
    • Host: macOS IP
    • Credentials: same private key or separate credential
    • Remote FS root: e.g. /Users/jenkins
  6. Assign a label like macos-agent, so jobs requiring macOS can run there.
  7. Sample pipeline specifying macOS agent:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    pipeline {
      agent { label 'macos-agent' }
      stages {
        stage('Test') {
          steps {
            sh 'swift --version'
          }
        }
      }
    }
    

🧪 Testing the Multi‑Agent Setup

  • Create or update Jenkins pipeline jobs:

    • One using docker-agent label → runs on the Linux LXC Docker slave.
    • One using macos-agent → runs on the macOS host.
  • Trigger builds via Jenkins UI accessible through your reverse proxy domain (e.g. jenkins.home.mydomain.com).
  • Verify:

    • The master shows executors 0, and builds go to agents.
    • Logs show build steps execute on the respective machines.
    • Docker containers build/run on LXC; macOS tools run on the macOS node.

🔐 Security & Maintenance Tips

  • Use SSH key authentication only-disable password login.
  • Restrict traffic to agents: only master’s host should SSH in.
  • Keep Jenkins and plugins up to date using in‑UI update centers.
  • Regularly update LXC base images, host OS, and macOS software.
  • Backup Jenkins config and credentials with [Jenkins backup plugins] or manual file backups.

🧼 Clean Code Sample: Docker Build Jenkinsfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pipeline {
  agent { label 'docker-agent' }
  stages {
    stage('Checkout') {
      steps {   
        checkout scm
      }
    }
    stage('Build & Test') {
      steps {
        sh '''
          docker build -t myapp:${env.BUILD_NUMBER} .
          docker run --rm myapp:${env.BUILD_NUMBER} ./runTests.sh
        '''
      }
    }
  }
}

This snippet follows clean code guidelines: readable stages, meaningful labels, minimal inline scripts, and environment‑driven versioning.


📋 Summary Cheat‑Sheet

ComponentRoleLabel
Jenkins MasterCoordinates builds, no actual execution(none, executors = 0)
Linux LXC SlaveRuns Docker‑based buildsdocker-agent
macOS SlaveExecutes macOS‑specific jobsmacos-agent
Reverse Proxy (NGM)TLS, public access routing to master-

Final Thoughts

✅ Setting up Jenkins with master coordinates only and agents doing all the work gives flexibility, isolation, and performance in a home‑lab context. ✅ Proxmox LXC is lightweight and ideal for consistent Linux build environments, especially with Docker. ✅ Adding a macOS SSH agent allows testing or building on Apple platforms when needed. ✅ Proper SSH key management, network restrictions, and regular updates ensure stability and security.

By following this setup, you gain a modular, maintainable, and secure CI platform at home. If you’re building cross‑platform tools, iOS apps, or containerized services, this architecture scales nicely.

This post is licensed under CC BY 4.0 by the author.