{"id":475,"date":"2026-10-14T16:11:17","date_gmt":"2026-10-14T16:11:17","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2016\/03\/10\/install-jenkins-using-docker\/"},"modified":"2026-10-14T16:11:17","modified_gmt":"2026-10-14T16:11:17","slug":"install-jenkins-using-docker","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/install-jenkins-using-docker\/","title":{"rendered":"Install Jenkins with Docker: Persistent Setup, Port Mapping, and Logs"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Running Jenkins in Docker is a practical way to launch a CI server quickly while keeping host setup simple. This guide is for DevOps engineers who want a repeatable Jenkins container setup with persistent data, correct port mapping for UI and agents, and day-2 commands for logs and troubleshooting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2016-03-10; fully revised and updated.<\/em><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2016\/03\/install-jenkins-using-docke.png\" alt=\"Install Jenkins using Docker\"\/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>A Linux host with Docker installed and running.<\/li><li>Access to run Docker commands (root or sudo-enabled user).<\/li><li>A network path to the host on the port you map for Jenkins UI (for example, 8080 or 49001).<\/li><li>Disk space for Jenkins home data (plugins, jobs, build history, configuration).<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Jenkins-on-Docker workflow<\/h2>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Install Docker] --> B[Pull Jenkins image]\n    B --> C[Prepare persistent data path]\n    C --> D[Run Jenkins container with ports and volume]\n    D --> E[Open Jenkins web UI]\n    E --> F[Get initial admin password]\n    F --> G[Complete Jenkins setup wizard]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Install Docker on the host<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The original article used the following package commands:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">apt-<span class=\"hljs-keyword\">get<\/span> install docker\nyum install docker<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">For additional context, the original post also referenced this Docker installation page: <a href=\"http:\/\/www.scmgalaxy.com\/scm\/software-containers\/how-to-install-docker-in-linux.html\" target=\"_blank\" rel=\"noopener\">http:\/\/www.scmgalaxy.com\/scm\/software-containers\/how-to-install-docker-in-linux.html<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Pull a Jenkins image<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The original command used <code>docker pull jenkins<\/code>. In current environments, you will commonly see Jenkins images referenced as <code>jenkins\/jenkins<\/code> with a tag.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs language-bash\">docker pull jenkins\/jenkins:lts<\/code><\/span><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Step 3: Run Jenkins container<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Quick start (no persistent host mapping)<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs language-bash\">docker run --name jenkins -d -p 8080:8080 -p 50000:50000 jenkins\/jenkins:lts<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This is fast for testing, but Jenkins data is not safely mapped to a host directory. If the container is removed, your Jenkins state can be lost.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Persistent setup (recommended)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">mkdir -p jenkins_home\nchown <span class=\"hljs-number\">1000<\/span>:<span class=\"hljs-number\">1000<\/span> jenkins_home\ndocker run --name jenkins -d -p <span class=\"hljs-number\">8080<\/span>:<span class=\"hljs-number\">8080<\/span> -p <span class=\"hljs-number\">50000<\/span>:<span class=\"hljs-number\">50000<\/span> -v <span class=\"hljs-string\">\"$PWD\/jenkins_home:\/var\/jenkins_home\"<\/span> jenkins\/jenkins:lts<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This follows the original post\u2019s core idea: mount <code>\/var\/jenkins_home<\/code> to the host so plugins, jobs, and configuration survive container recreation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Custom host port and root user variant (only if required)<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">docker run --name jenkins -d -u root -p <span class=\"hljs-number\">49001<\/span>:<span class=\"hljs-number\">8080<\/span> -p <span class=\"hljs-number\">50000<\/span>:<span class=\"hljs-number\">50000<\/span> -v <span class=\"hljs-string\">\"$PWD\/jenkins_home:\/var\/jenkins_home\"<\/span> jenkins\/jenkins:lts<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This keeps the original example of mapping host port <code>49001<\/code> to container port <code>8080<\/code>. Use <code>-u root<\/code> only when permissions force it; default non-root operation is generally safer.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Container options comparison<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Option<\/th><th>What it controls<\/th><th>Example<\/th><th>When to use<\/th><\/tr><\/thead><tbody><tr><td><code>-p 8080:8080<\/code><\/td><td>Jenkins web UI port mapping<\/td><td>Host 8080 to container 8080<\/td><td>Default local access pattern<\/td><\/tr><tr><td><code>-p 49001:8080<\/code><\/td><td>Custom host UI port<\/td><td>Host 49001 to container 8080<\/td><td>When 8080 is occupied or policy requires another port<\/td><\/tr><tr><td><code>-p 50000:50000<\/code><\/td><td>Inbound agent connection port<\/td><td>Host 50000 to container 50000<\/td><td>If you use inbound\/JNLP-style agents<\/td><\/tr><tr><td><code>-v host_path:\/var\/jenkins_home<\/code><\/td><td>Persistent Jenkins data<\/td><td><code>-v \"$PWD\/jenkins_home:\/var\/jenkins_home\"<\/code><\/td><td>Recommended for any non-ephemeral usage<\/td><\/tr><tr><td><code>-u root<\/code><\/td><td>Container user identity<\/td><td><code>-u root<\/code><\/td><td>Only for permission troubleshooting or specific admin tasks<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Get the initial password and check logs<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-bash\">docker exec jenkins cat \/<span class=\"hljs-keyword\">var<\/span>\/jenkins_home\/secrets\/initialAdminPassword\ndocker logs -f jenkins<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The original post showed log access via <code>docker exec name tail -f \/var\/log\/jenkins\/jenkins.log<\/code>. Depending on image layout, that file path may differ; <code>docker logs<\/code> is usually the most reliable first check.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Access Jenkins in the browser<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Open Jenkins at the host and port you mapped, for example:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>http:\/\/localhost:8080<\/code><\/li><li><code>http:\/\/localhost:49001<\/code> (if you mapped <code>49001:8080<\/code>)<\/li><li><code>http:\/\/&lt;host-ip&gt;:49001<\/code> from another machine<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Always persist <code>\/var\/jenkins_home<\/code> to avoid data loss during container replacement.<\/li><li>Use the least-privilege runtime user whenever possible; avoid permanent <code>-u root<\/code> operation.<\/li><li>Pin an explicit image tag instead of relying on floating defaults.<\/li><li>Expose port <code>50000<\/code> only if your agent model requires it.<\/li><li>Document your run command (or move to Docker Compose) so rebuilds are repeatable.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to run Jenkins in Docker with correct port mapping, persistent storage, and operational commands. This updated guide keeps the original workflow but adds modern, production-minded practices.<\/p>\n","protected":false},"author":1,"featured_media":3058,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[4862,42],"tags":[567,1122,545,1216,237,1215,145,1214,1217,1218,1219,593,732,213],"class_list":["post-475","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker","category-jenkins","tag-docker","tag-guide","tag-how","tag-how-to-install-jenkins-using-docker","tag-install","tag-install-jenkins-using-docker","tag-jenkins","tag-jenkins-installation-guide","tag-jenkins-installation-process","tag-jenkins-installation-tutorial","tag-jenkins-installation-using-docker","tag-process","tag-steps","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/475","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=475"}],"version-history":[{"count":8,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/475\/revisions"}],"predecessor-version":[{"id":79358,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/475\/revisions\/79358"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3058"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=475"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=475"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=475"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}