Setting up Jenkins using Caddy and Docker

Introduction / The Problem

Recently, I’ve encountered a problem. I host Jenkins and Nexus on one server. Nexus requires Java 8 while Jenkins recommends Java 11. I used to manually modify the init script every update to force the Java path. However, with a recent update, Jenkins changed the script so my “hack” wasn’t working anymore. I decided to solve things once and for all by putting Jenkins and Nexus in Docker containers. However, this tutorial will only show you how to setup Jenkins while using Caddy as a reverse proxy so you can use a domain with HTTPS.

Prerequisites

Firstly, you’ll want to make sure you actually have Docker installed. To verify, you can run the following:

docker version

If you get an output, you’re all set. If Docker isn’t installed, you can install it with the following command:

curl -sSL https://get.docker.com/ | CHANNEL=stable bash

Installing Caddy

For this tutorial, we will be using Caddy as the webserver. The reason for using Caddy is because Caddy offers automatic HTTPS certificates, and it’s super easy to setup a reverse proxy. Run the following commands to install Caddy:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-stable.asc
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Commands retrieved from https://caddyserver.com/docs/install#debian-ubuntu-raspbian on March 24, 2022.

If you go to your server’s IP address, you should see a page that welcomes you to Caddy. If you have another webserver installed, you can setup a reverse proxy with that. However, it is much more complicated, which is why we will be using Caddy. If you don’t see the webpage generated from Caddy, you likely have another webserver installed and in use already. This tutorial won’t cover setting up reverse proxies with other servers such as Apache or nginx.

Running the Container

If you want to cut to the chase, here’s the command:

docker run --name jenkins --privileged -d -v jenkins_home:/var/jenkins_home -p 127.0.0.1:8080:8080 -p 127.0.0.1:50000:50000 jenkins/jenkins:jdk11

Here’s what this command does: It will run a new container with the name “jenkins-docker”. If you don’t specify a name, it will generate a random one for you. The privileged flag will run it in privileged mode which may be required depending on how you use Jenkins. The -d flag simply tells it to run detached. If you don’t include that flag, you will see all of the logs from the container. The -v jenkins_home:/var/jenkins_home creates a new volume for your Jenkins home. The -p 8080:8080 -p 50000:50000 maps the appropriate ports for Jenkins. If you want to host it on a different port, you’ll want to change the first port. So, if you wanted to run it on 8081, you’d change -p 8080:8080 to -p 8081:8080. The last part simply tells Docker to use the Jenkins image for JDK 11.

Note that there are two Docker images: jenkins/jenkins:jdk11 and jenkins/jenkins:lts-jdk11. If you want the LTS version, you’ll need to use the second one. The LTS version receives updates less often. However, Docker images are relatively easy to update, so we’ll be using the image that gets updated more often. I will show you how to update the container and image whenever there’s a new update at the end of this tutorial.

If everything goes well, you should be able to run the following to see logs:

docker logs jenkins

It may take a minute or two to say everything was successful. If that’s the case, we can now setup Caddy.

The Caddy Configuration

To actually change the settings for Caddy, we use the Caddyfile. On Ubuntu, the Caddyfile should be at: /etc/caddy/Caddyfile. Use your preferred text editor to open the Caddyfile.

nano /etc/caddy/Caddyfile

Unless you have other things setup with Caddy, you can delete all the sample code. Replace the <domain> with your actual domain. For example, if I wanted to host it at https://ci.plex.us.org, I’d enter ci.plex.us.org in place of <domain>. Do not include the “< >” symbols, just the domain. If you decided to use anything other than port 8080, you’ll want to change that as well. If I were to use port 8081, the line would be reverse_proxy http://localhost:8081 instead.

<domain> {
	reverse_proxy http://localhost:8080
}

Seriously, it’s that dead simple. That’s how you setup a reverse proxy with HTTPS using Caddy. It’s much easier than Apache or nginx.

Once you’ve done that, run the following to restart Caddy:

sudo service caddy restart

At this point, you should be able to access the Jenkins installation page at the domain you specified in the Caddyfile. You will be prompted for a secret password. This was outputted in the container after it was started up. If you need a reminder, the command is docker logs jenkins-docker. The password will be displayed there. You need to copy that to the web interface. At that point, you can follow the rest of the prompts to setup Jenkins. However, we still have one problem. If you restart your server, the container won’t start. You’ll need to make change the command slightly to solve this.

Making Jenkins restart

If everything has gone well, you can now stop Jenkins

docker stop jenkins

Now, all you need to do is use this command instead.

docker run --name jenkins -d --restart unless-stopped --privileged -v jenkins_home:/var/jenkins_home -p 127.0.0.1:8080:8080 -p 127.0.0.1:50000:50000 jenkins/jenkins:jdk11

Jenkins will now start automatically whenever your server reboots. However, it will not automatically restart if you manually stop it.

Updating Jenkins

To update it, you’ll want to stop the jenkins container, remove it, pull the image, and then start it again. The following commands should do it:

docker stop jenkins
docker rm jenkins
docker pull jenkins/jenkins:jdk11
docker run --name jenkins -d --restart unless-stopped --privileged -v jenkins_home:/var/jenkins_home -p 127.0.0.1:8080:8080 -p 127.0.0.1:50000:50000 jenkins/jenkins:jdk11

Note that removing the container shouldn’t delete any of your data if you followed the tutorial correctly. You shouldn’t need to modify anything else as long as the container name and port mappings match up with what you had before.

This is honestly my first time ever writing a blog post, and I’m doing this at around 2 am on a caffeine rush. Hope this helps someone.