Robot Cottage

So, you want to install Caddy

Here are my findings installing the latest version of Caddy on Ubuntu.

If you don't know what Caddy is, it's a modern, standalone, single-executable webserver. Its claim to fame is that it automatically obtains and renews TLS certificates using LetsEncrypt.

My last webserver configuration job about four years ago was with nginx, and I spent some quality time configuring it for HTTPS using cron and certbot. Certbot fiddles with the nginx config file, writing some lines in it. Now the config file consists of my hand-written lines interspersed with Certbot-generated lines. I am hesitant to edit the config file myself.

I'm not confident I remember how to do it again. My webserver configuration works, but it feels brittle and I don't want to break it. I would like to avoid that experience if possible, hence I'm trying out Caddy.

The detailed instructions on various sites are out of date, so I am recording what works for me here as of May 2024.

My requirements

The webserver is written in Go, but I intend to use it out-of-the-box using its reverse-proxy features and built-in modules instead of trying to extend it using Go. So, I don't care to look into its sources.

I normally work on my own Ubuntu laptop, so I plan to get it working first on my laptop under localhost, and then recreate it on the public server. There are certain differences between these two configurations. Also, the configuration on debian-based distros like Ubuntu is different from Fedora-based distros or Arch-based distros. So, I am recording exactly what I did below.

My server

Downloading Caddy

Since I don't need to build Caddy from source, I used its official instructions to download the debian package directly from dl.cloudsmith.io. It involves running an incantation to download a GPG key and adding a new repo to /etc/apt/sources.list.d.

When you install the debian package, it automatically creates and runs a systemd service named caddy, after creating a new user and group named caddy.

$ systemctl status caddy
● caddy.service - Caddy
     Loaded: loaded (/lib/systemd/system/caddy.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-05-27 21:18:24 EDT; 1 day 17h ago
       Docs: https://caddyserver.com/docs/
   Main PID: 8087 (caddy)
      Tasks: 15 (limit: 38003)
     Memory: 9.2M
        CPU: 12.179s
     CGroup: /system.slice/caddy.service
             └─8087 /usr/bin/caddy run --environ --config /etc/caddy/Caddyfile

Caddy user home directory

The installation chose to create the Caddy user's home directory under /var/lib, it seems because of some permissions issues with accessing /home for a service running under systemd. It took me some time to figure this out. I was looking for the home directory and couldn't find it immediately.

It turns out the location of the home directory is important, because by default, Caddy stores TLS certificates somewhere under the home directory. More on this later.

HTTPS on local versus public server

The biggest difference between my laptop and the public server is that the TLS certificates are generated differently: on the public server, my DNS domain name will be certified by a public Certificate Authority like LetsEncrypt, and Caddy will exchange ACME messages with the CA to get this done. But for the Caddy server running on my laptop as https://localhost, Caddy will create its own CA. This difference doesn't matter for how the webserver will be used, but it matters for how the certificates will be generated.

File locations on the local server

The installer in the debian package initially creates an HTTP server listening on TCP port 80. The Caddyfile, the simplified configuration file for the webserver, is placed under /etc/caddy, and it's owned by root:

  $ ls -ltd /etc/caddy
  drwxr-xr-x 2 root root 4096 May 29 14:41 /etc/caddy/

Here's what's in the default Caddyfile, removing lots of comments:

:80 {
	# Set this path to your site's directory.
	root * /usr/share/caddy

	# Enable the static file server.
	file_server

	# Another common task is to set up a reverse proxy:
	# reverse_proxy localhost:8080
}

You can see above that:

The caddy webserver is running fine. I can go to "localhost" in my browser and see a big page full of information from Caddy.

Setting up HTTPS on the laptop

On my laptop, I have to run caddy trust so that Caddy will create a CA and store it in the "local trust store", /etc/ssl/certs. After that, Caddy will use this CA to sign my localhost TLS certificate. It keeps the certificates under its home directory /var/lib/caddy, inside .local/share/caddy/pki/authorities/local.

I then modified the Caddyfile to enable HTTPS by replacing the :80 with localhost, which will cause Caddy to start listening on port 443 and automatically redirect HTTP connections to it. I also named /var/www as the root directory, as recommended:

localhost {
	# Set this path to your site's directory.
	root * /var/www

	# Enable the static file server.
	file_server
}

To create the new root directory, I had to make sure it belonged to user Caddy:

$ sudo mkdir /var/www
$ sudo chown caddy:caddy /var/www

Then I edited an "index.html" inside the root directory, running my editor as Caddy.

When I reloaded the Caddy webserver with systemctl, then typing localhost in my browser started connecting to the HTTPS website. It works!

I am now the proud owner of an HTTPS website on my laptop.

My next step will be to install Caddy on a VM in the cloud.

See Part 2 of my website adventures.

#tech