What the controller needs
| Item | Figure from the Jenkins docs |
|---|---|
| Minimum hardware | 256 MB RAM, 1 GB of drive space |
| Small team, recommended | 4 GB+ RAM, 50 GB+ of drive space |
| Java runtime | Java 21 or Java 25, 64-bit |
| HTTP listener | Port 8080 on 0.0.0.0 by default |
| State | JENKINS_HOME, /var/lib/jenkins on the Debian package |
Controller memory depends on many factors, and the hardware recommendations page says to estimate it from your project build needs. The hardware recommendations page gives a range from 200 MB for a small installation to 70+ GB for one massive controller, and counts each connected build node at 2-3 threads, about 2 MB or more. The CPU and disk that compilers, containers and test suites eat belong on agents.
Java is a hard gate. The support policy lists Java 21 (from LTS 2.479.1, planned end of support September 2027) and Java 25 (from LTS 2.541.1, planned end September 2029). Java 17 stopped at LTS 2.541.3, and the policy says a controller on an unsupported Java version will not run.
LTS or weekly
Jenkins ships two release lines. The LTS line picks a baseline every 12 weeks and publishes stable releases every 4 weeks carrying backported bug and security fixes; the weekly line delivers fixes and features about once a week. The current LTS is 2.580.1, dated 30 September 2026 and tested on JDK 21 and 25. A controller other people depend on should track LTS, from the debian-stable repository.
Why the controller gets its own machine
JENKINS_HOME holds every job definition, the build history, the plugins and the encrypted credentials your pipelines use to reach repositories and deploy targets. On a dedicated server that directory sits on disks no other customer touches: the entire machine, root, and an operating system you can reinstall from the control panel as often as needed.
- Every racked single-, dual- and quad-socket server has an out-of-band console (HPE iLO, Dell iDRAC or a Supermicro BMC), so a firewall rule that drops SSH is fixed from the console, not by ticket. So do the m510 and m710x Moonshot cartridges; the rest of the cartridges have power control only.
- Ports marked Unmetered carry no transfer allowance and no overage fee, so plugin updates, artifact downloads and agent traffic are not metered.
- The network is our own autonomous system, AS19624, with no upstream reseller between you and the metal.
Matching lines to controller and agents
- Controller only: a single-socket server, the line the range describes as the base for an application host, or a Moonshot cartridge if the controller is the one service on the box.
- Build agents: the desktop platforms, Intel Core with NVMe storage and a dedicated GPU, which the range lists for CI runners.
- Many executors on one box: a dual-socket server carrying several agent VMs or containers side by side.
- Odd requirements: a build to your specification, handed over in 4 to 24 hours.
A racked machine is handed over in about 30 minutes once payment is approved. Add IPv6 at checkout, at no charge, if your agents or users reach the controller over it.
Installing the LTS on Ubuntu 24.04
- Open
/etc/default/ufwand make sure it readsIPV6=yes, so every rule also applies to IPv6, then turn ufw on with SSH as the only allowed service. The package registers Jenkins as a service that starts on its own, listening on port 8080 on all interfaces (0.0.0.0 by default), so the firewall must already be dropping that port before you install. - Install OpenJDK 21 before Jenkins. The guide warns that installing Java afterwards can leave the service failing with
jenkins: failed to find a valid Java installation. - Add the signing key and the
debian-stablerepository, then install. The key file is named for its year; copy the current name from the Linux install page.
grep IPV6 /etc/default/ufw # expect IPV6=yes
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verbose # v6 rules listed too
sudo apt update
sudo apt install fontconfig openjdk-21-jre
java -version
sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc \
https://pkg.jenkins.io/debian-stable/jenkins.io-2026.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 jenkins
The package creates a jenkins user, a systemd unit and the home in /var/lib/jenkins, and logs to the journal: journalctl -u jenkins.service.
Unlocking the wizard over loopback
Until the wizard is finished, whoever reaches port 8080 with the initial password gets to set the instance up. Bind Jenkins to 127.0.0.1 with a systemd drop-in. This is our combination of two documented pieces: the initial-settings page documents --httpListenAddress, and the systemd page shows extra arguments going in through JENKINS_OPTS. Run sudo systemctl edit jenkins and type these two lines in the editor, then save; they are settings, not shell commands.
[Service]
Environment="JENKINS_OPTS=--httpListenAddress=127.0.0.1"
- Apply the drop-in with
sudo systemctl restart jenkins, then confirm withsudo ss -ltnp | grep 8080that the listener is 127.0.0.1:8080. - From your workstation, open a tunnel over your own SSH login:
ssh -L 8081:127.0.0.1:8080 you@your-server. - In that SSH session, print the file
initialAdminPasswordfrom/var/lib/jenkins/secrets/with sudo cat. - Open http://localhost:8081 on the workstation and paste the password into the Unlock Jenkins page.
- Choose Install suggested plugins unless you already know the set you need.
- Create the first admin user. If you skip this step, the initial password stays the password of a user named admin.
nginx in front of port 8080
Jenkins stays on loopback for good; nginx takes the public side. This is the official fragment trimmed to its proxy block, with the static-file shortcuts left out and one IPv6 line added. The Upgrade and Connection headers are what WebSocket agents need.
upstream jenkins {
keepalive 32;
server 127.0.0.1:8080;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' '';
}
server {
listen 80;
listen [::]:80; # IPv6: our addition
server_name jenkins.example.com;
ignore_invalid_headers off;
location / {
sendfile off;
proxy_pass http://jenkins;
proxy_redirect default;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_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_max_temp_file_size 0;
client_max_body_size 10m;
proxy_request_buffering off;
}
}
The listen [::]:80; line is ours, not in the official fragment: without it nginx answers on IPv4 only. When you add the certificate, repeat it as listen [::]:443 ssl next to the IPv4 443 listener. Do not end proxy_pass with a slash; the docs warn it causes problems. The fragment listens on plain HTTP, so put TLS in place before the first login from outside, let 80,443/tcp through ufw, and set the public address under Manage Jenkins » System » Jenkins URL.
Agents, permissions and CSRF
- Built-in node at 0 executors. Builds on it have the same access to the controller file system as the Jenkins process. Set it under Manage Jenkins » Nodes, Built-In Node, Configure, after an agent exists.
- No second machine yet? The controller-isolation page allows a second agent process on the controller's own hardware, running as another OS user, with no read or write access to JENKINS_HOME and no sudo.
- Agent ports. The inbound TCP agent port is disabled by default; WebSocket agents (Jenkins 2.217 and later) connect through the proxy above with no extra port.
- Access control. The wizard leaves Logged-in users can do anything, which is only safe while every account is fully trusted. Never enable sign-up with it; move to a matrix strategy before adding less trusted users.
- CSRF. Leave crumb protection on. Scripts should authenticate with a username and API token, which is exempt from the crumb check.
Backups and the controller key
Back up JENKINS_HOME: the *.xml configuration files, jobs/ with build history and archived artifacts (the latter can grow very large), and the plugin packages. Workspaces, war/, cache/ and tools/ can be rebuilt. Filesystem snapshots on LVM, btrfs or ZFS give the most consistent copy. Copy each backup off the machine.
The backup guide says never to put the controller key in routine backups. secrets/master.key is the controller key: it encrypts secrets/hudson.util.Secret, which secures stored credentials, and anyone holding both the key and a backup has full access. Keep it separately, somewhere secure, and restore it last. Test each backup by restoring it to a scratch directory and starting it on another port.
Questions
How much memory should a Jenkins controller get?
The install guide recommends 4 GB+ for a small team, against an absolute floor of 256 MB. The hardware page notes that installations range from 200 MB to more than 70 GB for one very large controller, with each connected agent taking 2-3 threads, about 2 MB or more, and many web UI users adding CPU overhead. Start at the small-team figure on a machine with room to add memory.
Can builds run on the same server as the controller?
Not on the built-in node: the Jenkins docs advise against it because those builds can read and write the controller's files. If one machine is all you have, run an agent process under a separate OS user that cannot touch JENKINS_HOME or use sudo, and set the built-in node to zero executors.
Which Java does the current Jenkins LTS need?
Java 21 or Java 25. LTS 2.580.1 was tested on JDK 21 and 25, and the last LTS to accept Java 17 was 2.541.3. On Ubuntu, openjdk-21-jre from the distribution is what the install guide uses.
Does the server need ports open for agents?
Not if agents connect over WebSocket through the reverse proxy, which needs only 80 and 443. The separate inbound TCP agent port is off by default; if you turn it on, give it a fixed number so a firewall rule can name it.
Jenkins, or the CI that comes with my Git host?
Jenkins is a standalone automation server with its own plugin ecosystem and agents, independent of where the code lives. If the repositories already sit in GitLab or Gitea, their built-in pipelines may be enough: see self-hosted GitLab and Gitea with its runners. For GitHub repositories, compare a self-hosted Actions runner.