Running a Caddy web server

Up until recently, my server was running Nginx to serve my website and a few other projects/tools. After running into a few issues while setting up Jenkins (a CI/CD tool), I started keeping an eye out for alternatives which would solve these issues while making the process of reconfiguring my server easier.

The problem: Jenkins was running on my server, and configured to be accessible through a path on my main domain (eg. Since Jenkins runs its own server, requests to are forwarded from Nginx to the Jenkins server.

Due to how Nginx escapes URIs in this specific case, Jenkins continued claiming the configuration was incorrect. Jobs were still running correctly, but to avoid any unintended (or difficult to discover) side-effects, I wanted to get around this issue once and for all without having to set up a subdomain.

The solution: I came across Caddy through a post on Hacker News. After some digging it looked like this could be a good candidate to replace Nginx as it would solve my issues with Jenkins and also make modifications to my web server configuration much simpler. As a bonus, Caddy automatically configures SSL, making the setup of new domains and subdomains much simpler.

Installing go

At the time of writing, Go 1.15 had just been released and Caddy did not have full compatibility, so I downloaded Go 1.14.7.

To extract the tarball, run sudo tar -C /usr/local -zxf go1.14.7.linux-amd64.tar.gz. This will extract Go into /usr/local/go.

In order to make go usable from the command line, it must be added to the PATH environment variable. I already make modifications my PATH in ~/.zshrc, otherwise add the following to your ~/.bashrc or ~/.zshrc depending on your shell (or /etc/profile for system-wide installation); export PATH=$PATH:/usr/local/go/bin

Installing Caddy

Caddy can either be built from source using the instructions on the project’s GitHub profile or by downloading a prebuilt binary from the Caddy website.

No matter which alternative is used, you will end up with a single caddy binary. Installing the binary can be done by running sudo cp caddy /usr/bin/caddy on the command line.

After installing the binary, a caddy user and group must be added by running the following commands;

$ sudo groupadd --system caddy

$ sudo useradd --system \
    --gid caddy \
    --create-home \
    --home-dir /var/lib/caddy \
    --shell /usr/sbin/nologin \
    --comment "Caddy web server" \

Finally, a systemd service must be installed to be able to run automatically on system startup. If your configuring Caddy through its API, use caddy-api.service, or if you prefer a file-based configuration use caddy.service, both available on GitHub.

No matter which systemd file is used, install the file to /etc/systemd/system/caddy.service, and then run the following commands to enable the Caddy service and run it;

$ sudo systemctl daemon-reload
$ sudo systemctl enable caddy
$ sudo systemctl start caddy

Configuring Caddy

There are several different ways to configure Caddy, outlined in the documentation. Either through an API, Caddyfile or a JSON config file.

I chose to use a Caddyfile (located in /etc/caddy/Caddyfile) to allow for an easy overview of the configuration. There are two things to achieve;

  1. Set up the main server configuration.
  2. Configure a reverse proxy for Jenkins.

1. Main server configuration

There are a couple of parts to this; choosing the server root for and forwarding all requests from to {
	# Direct all requests to to files in /var/www
	root * /var/www

	# Serve up files as a static file server

# Remove www. from all requests to the website {

2. Configure a reverse proxy for Jenkins

Thankfully, the configuration for this is much simpler than in Nginx. Only one line needs to be added to the Caddyfile as shown below; {
	# Direct all requests to to files in /var/www
	root * /var/www

	# Reverse proxy for Jenkins
	# All requests to will be redirected
	# to localhost:8000
	reverse_proxy /jenkins/* localhost:8080

	# Serve up files as a static file server

# Remove www. from all requests to the website {

After all of this had been done, sudo systemctl restart caddy was the last thing required to finalise the process.