jenkinsci/docker: the official Jenkins image, what it bundles and how to run it
Docker official jenkins repo
At a glance
- What is it?
- The jenkinsci/docker repository builds and publishes the official jenkins/jenkins images on Docker Hub. It gives you a working Jenkins controller from a single docker run, with the data in a volume and the controller left idle by default.
- Who is it for?
- Adopt this image if you want a Jenkins controller you can start with one docker run and treat like a database, with the workspace on a named volume and agents attached over port 50000 or SSH. Do not adopt it if you expected the image to contain your plugins, jobs or build tools: the README treats the image as a base to extend with a Dockerfile and COPY --chown=jenkins:jenkins, and the plugin installation script is a separate mechanism.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly PowerShell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What jenkinsci/docker actually ships
This repository is not a Jenkins plugin or a wrapper library. It is the build system and documentation behind the jenkins/jenkins images on Docker Hub, which the README describes as "a fully functional Jenkins server". Everything a Jenkins installation needs at runtime lives in /var/jenkins_home: the README states that all Jenkins data lives there, including plugins and configuration, and that the workspace is stored there too.
The repository layout shows how that image is produced. There are separate alpine/, debian/, rhel/ and windows/ directories, a docker-bake.hcl plus a docker-bake.override.json for multi-target builds, a Makefile that drives hadolint, shellcheck, build and test, and a tests/ directory. That structure tells you the image is assembled from a base OS image plus Jenkins-specific layers, not from a single hand-written Dockerfile at the root. The audience is anyone who wants Jenkins without managing a JVM, a WAR file and an init system: CI teams, platform engineers, and people who need a disposable controller they can rebuild from a volume.
The licence is MIT, per the repository metadata, and LICENSE.txt sits at the top level. That covers the repository's own scripts and build files. The Jenkins application itself and any plugins you install carry their own terms, and the README does not discuss them.
How the image is built and what runs at startup
The Makefile is the entry point for building the images. It exports DOCKER_BUILDKIT=1, DOCKER_CLI_EXPERIMENTAL=enabled and BUILDKIT_PROGRESS=plain, derives OS from uname (Linux and Darwin both map to linux, MINGW/MSYS/CYGWIN map to windows) and ARCH from the machine type (x86_64 to amd64, aarch64 or arm64 to arm64). It also exports COMMIT_SHA from git rev-parse HEAD so the commit lands as an image label.
The build itself goes through docker buildx bake, with the base command defined as bake --file docker-bake.hcl --file docker-bake.override.json --load. That override file is how the project layers platform-specific or local changes on top of the manifest. The default target is set by bake_default_, and the Makefile includes a check_image macro that greps the output of make list to confirm a named image exists for the current OS/ARCH pair before proceeding.
At runtime, the container entrypoint is jenkins.sh (with jenkins.ps1 for the Windows variant). The scripts jenkins-support and jenkins-plugin-cli.sh are the plugin installation path, and jenkins-support.psm1 plus jenkins-plugin-cli.ps1 are their PowerShell counterparts. The README does not document the entrypoint's full startup sequence, so treat the shell scripts in the repository as the source of truth if you need that detail. What the README does describe is the observable result: the container starts Jenkins, writes its state under /var/jenkins_home, and prints an initial admin password to that directory.
Installing it and getting to the setup wizard
The README gives the run command directly. This starts the LTS image on JDK 21, publishes the web UI on 8080 and the inbound agent port on 50000, and restarts the container on failure:
docker run -p 8080:8080 -p 50000:50000 --restart=on-failure jenkins/jenkins:lts-jdk21That works, but the README warns against leaving the workspace implicit. Add a named volume so the data survives container replacement:
docker run -p 8080:8080 -p 50000:50000 --restart=on-failure -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk21Docker creates the jenkins_home volume on the host, and the README notes that volumes retain their content when the container is stopped, started or deleted. For a background run, the README's detached form adds -d and keeps the same volume and port mappings:
docker run -d -v jenkins_home:/var/jenkins_home -p 8080:8080 -p 50000:50000 --restart=on-failure jenkins/jenkins:lts-jdk21To finish the first login you need the initial admin password. The README offers two routes: read the container logs, or read the file directly.
docker exec <jenkins_container_id_or_name> cat /var/jenkins_home/secrets/initialAdminPasswordReplace the placeholder with the real container ID or name from the docker run output. After that, the README points to the installation guide's setup wizard at jenkins.io/doc/book/installing/docker/#setup-wizard. One practical warning the README raises: if the first startup shows "This Jenkins instance appears to be offline" and the logs contain java.net.UnknownHostException: updates.jenkins.io, the container is failing to resolve DNS names, and starting it with an explicit DNS server is the suggested fix.
Giving the controller zero executors
The image ships with two executors on the built-in node. The README states that default explicitly and then recommends zero, which is the Jenkins project's own position: builds belong on agents, not on the controller. Changing it means extending the image, not passing a flag. You write a Groovy init script and copy it into the init.groovy.d directory.
import jenkins.model.*
Jenkins.instance.setNumExecutors(0) // Recommended to not run builds on the built-in nodeFROM jenkins/jenkins:lts
COPY --chown=jenkins:jenkins executors.groovy /usr/share/jenkins/ref/init.groovy.d/executors.groovyThe --chown=jenkins:jenkins is not decorative. The README notes the jenkins user inside the container is uid 1000, and that a bind mount from a host folder into /var/jenkins_home can fail on permissions because that uid may not own the host directory. The same reasoning applies to files you copy in. If you must bind mount, the README says to make the host directory accessible to uid 1000 or pass -u some_other_user to docker run.
Once the controller has no executors, agent connectivity becomes the thing you actually have to configure. Port 50000 is only needed for inbound TCP agents. The README is explicit that SSH (outbound) agents and WebSocket-connected agents do not use that port, because those connections originate from the controller. Mapping 50000 when you only use SSH agents is harmless but unnecessary.
JVM settings, logging and reverse proxies
Two environment variables control the JVM, and the distinction matters. JAVA_OPTS is the general variable, and the README warns that other tools may also respond to it. JENKINS_JAVA_OPTS is the one for options that should apply specifically to the Jenkins controller. The README's example sets a footer URL through JAVA_OPTS:
docker run --name myjenkins -p 8080:8080 -p 50000:50000 --restart=on-failure --env JAVA_OPTS=-Dhudson.footerURL=http://mycompany.com jenkins/jenkins:lts-jdk21Logging goes through a java.util.logging properties file. The README's example writes data/log.properties with a ConsoleHandler at FINEST level and a jenkins.level of FINEST, then points the JVM at it and bind mounts the directory:
mkdir data
cat > data/log.properties <<EOF
handlers=java.util.logging.ConsoleHandler
jenkins.level=FINEST
java.util.logging.ConsoleHandler.level=FINEST
EOF
docker run --name myjenkins -p 8080:8080 -p 50000:50000 --restart=on-failure --env JAVA_OPTS="-Djava.util.logging.config.file=/var/jenkins_home/log.properties" -v `pwd`/data:/var/jenkins_home jenkins/jenkins:lts-jdk21Note the bind mount in that example, which sits awkwardly next to the README's own warning about bind mounts and uid 1000. It is a documentation example, not a recommendation, and the permission caveat still applies. For a reverse proxy under a path prefix such as mysite.com/jenkins, the README says to set JENKINS_OPTS="--prefix=/jenkins" and then follow the separate Apache or Nginx configuration guides on jenkins.io. The repository does not contain those proxy configs.
Where this image is the wrong choice
The image is a controller, not a build environment. If your jobs need compilers, language runtimes or SDKs, they need to be on agents or in separate build images. Nothing in the README suggests the jenkins/jenkins image carries a toolchain, and the recommendation to run zero executors on the built-in node points the other way.
Backup is the second boundary. The README treats /var/jenkins_home as a database and says to back up the volume directory. Its own caveat is worth repeating: docker cp $ID:/var/jenkins_home can convert some symlinks into copies on certain operating systems, which the README says can confuse Jenkins with lastStableBuild links. If you rely on those links, docker cp is the wrong extraction method.
Configuration as code is the third. The README documents a Groovy init script for executors and environment variables for the JVM and for the URL prefix. It does not document a declarative configuration file for jobs, credentials or plugin sets, and it does not document rollback of an image upgrade. If your requirement is a fully reproducible controller defined in a file you can review, this repository gives you the image and the init.groovy.d hook, and you supply the rest. Anyone expecting the image to be a complete, self-describing deployment should look at the wider Jenkins tooling instead.
What you would use instead
The most direct alternative is a Jenkins installation from the native packages or the WAR file, which the README implicitly contrasts with by pointing at jenkins.io for the application itself. The difference is where the runtime boundary sits. With this image, the OS packages, the JVM and the Jenkins version are fixed by the tag you pull, and upgrades mean pulling a new tag and restarting against the same /var/jenkins_home volume. With a WAR file on a host, you own the JVM version, the service definition and the upgrade order, and you can patch the JDK without rebuilding anything.
A second alternative, for teams that want build definitions in the repository rather than a long-lived controller, is to use a hosted CI service. The trade-off is not subtle: this image gives you a Jenkins controller you operate, with plugin installation through the repository's own scripts and state on a volume you back up. A hosted service removes that operational surface but also removes the plugin ecosystem and the Groovy-level control the init.groovy.d directory provides. Choosing between them is a question of whether you want to run the controller at all.
Maintenance, releases and licence
The repository is not archived, and the last push was on 2026-09-21. Recent releases follow a weekly cadence: 2.582 on 2026-09-15, 2.581 on 2026-09-08, and 2.580 on 2026-09-02. That cadence matters for pinning. If you track lts-jdk21 you get the LTS line the README uses in every example; if you pin an exact version you take on the upgrade work yourself.
The upgrade cost is mostly the volume. Because all state lives in /var/jenkins_home, moving to a new image tag means starting a new container against the existing volume. The README does not document a rollback path, so the practical safeguard is a copy of the volume before you pull a new tag. Plugin compatibility is the usual source of surprises on a Jenkins upgrade, and the README does not discuss plugin version constraints.
On licensing, the repository is MIT, which is permissive and places few obligations on how you redistribute the build files. That is the repository, not the runtime. The Jenkins application and every plugin you install through the plugin CLI carry their own licences, and this repository does not enumerate them. If you redistribute a built image commercially, check those separately rather than assuming the MIT header at the root covers the whole artifact.
Editorial conclusion
Adopt this image if you want a Jenkins controller you can start with one docker run and treat like a database, with the workspace on a named volume and agents attached over port 50000 or SSH. Do not adopt it if you expected the image to contain your plugins, jobs or build tools: the README treats the image as a base to extend with a Dockerfile and COPY --chown=jenkins:jenkins, and the plugin installation script is a separate mechanism. Before rolling it out, verify the tag you pin (lts-jdk21 is the one the README uses), whether port 50000 is reachable for inbound agents, and that your host can resolve updates.jenkins.io so the instance does not start offline.
Frequently asked questions
How do I install jenkinsci/docker on Linux?
Install Docker, then run the image the README uses, for example docker run -p 8080:8080 -p 50000:50000 --restart=on-failure -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk21. The named volume keeps all Jenkins data in /var/jenkins_home across container restarts.
Where does the jenkinsci/docker image store its data?
The README states that the workspace is stored in /var/jenkins_home and that all Jenkins data lives there, including plugins and configuration. It recommends a named volume rather than a bind mount, because a host folder may not be writable by the jenkins user inside the container, which is uid 1000.
How do I get the initial admin password for the jenkinsci/docker container?
Read the container logs, or run docker exec <jenkins_container_id_or_name> cat /var/jenkins_home/secrets/initialAdminPassword, replacing the placeholder with the real container ID or name. The README then directs you to the setup wizard in the Jenkins installation guide.
Do I need to map port 50000 when running jenkinsci/docker?
Only for agents that connect through an inbound TCP connection. The README says the port is not required if you use SSH (outbound) build agents, and it is not used for agents connected over WebSockets, since those connections are established from the controller.
How do I change the number of executors in the jenkinsci/docker image?
Extend the image and copy a Groovy init script into /usr/share/jenkins/ref/init.groovy.d/. The README's example calls Jenkins.instance.setNumExecutors(0) and copies it with COPY --chown=jenkins:jenkins, noting the default is two executors and that zero on the built-in node is recommended.
How do I set JVM options for jenkinsci/docker?
Use the JAVA_OPTS or JENKINS_JAVA_OPTS environment variables. The README advises JENKINS_JAVA_OPTS for options specific to the Jenkins controller, because other tools may also read JAVA_OPTS.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jenkinsci-docker)