Over the last 15+ years I’ve worked with a bunch of different web servers from Apache to Lighttpd to nginx. I like a hassle free life so while I’m typically an early adopter, I don’t tend to move on a whim unless I’m seeing a lot of positive feedback. A lot of my peers have been recommending Caddy for a while and I recently tried using it at work which finally convinced me to make the switch.

Why I’m moving

SSL Configuration is annoying

I self-host a bunch of applications and up to now I’ve typically run them in docker and used nginx to listen for incoming traffic to different domains and subdomains and forward traffic to the right container. This wasn’t too painful because I was running on HTTP with no SSL until the internet community (quite rightly) decided that we should SSL/TLS encrypt all traffic and LetsEncrypt made that trend easy by giving out free signed SSL certificates to all (10+ years ago it was pretty common that you’d pay an oligarchy of big companies to sign your SSL cert). I wouldn’t say configuring SSL in nginx is a tremendous PITA but it’s certainly not fool proof. I’m a fully qualified fool and I’ve broken it many times.

This process certainly got easier with Certbot which automatically configures your nginx certificates for you and can be run in a cron job to renew your certs on the regular but certbot dropped support for my OS a couple of years ago and require use of snap packages which until very recently have been broken on my server due to weirdness when I upgraded from an old version of Debian (I understand their reasoning although it is obviously a tad frustrating).

Server configuration in general is a pain

The nginx config file format is relatively verbose (compared to Caddy) and requires a lot more manual tweaking for my use case .e.g which headers need to be forwarded to the application, which . Whilst some folks might want to be able to manually tweak these config values, I do not want or need to care about them for my simple home server/self hosting set up - I’m not expecting to load balance millions of visitors to my websites or anything.

Fewer moving parts

Related to the first point really: maintaining good SSL certs in nginx requires that I have certbot correctly set up, configured and running in a cron job regularly as well as my nginx instance and my hosted apps. Caddy manages its own SSL certificates as part of the core application so I don’t need to run certbot alongside it.

In Summary

Nginx is a good bit of kit and it’s served me well for about a decade but I think the QoL that Caddy brings really makes switching worthwhile. I wouldn’t say nginx’s config system is bad or that I can’t use it but I’d say it has put me off standing up new web apps because of the faff adding a new site configuration would cause.

Installing Caddy and Replacing nginx

Firstly, on my debian box I followed the instructions here and installed caddy via the apt mirror.

Next I modify the caddy configuration file. For each domain I want to port forward I just add a simple declaration like so:

app.example.me {
    reverse_proxy 127.0.0.1:1234
}

app2.example.me {
    reverse_proxy 127.0.0.1:1235
}

app3.example.me {
    reverse_proxy 127.0.0.1:1236
}

This is so nice in comparison to nginx where I’d have to cook up a bunch of directives and pass in which ports I want it to listen on and paths to SSL keys and a 2nd configuration which listens for non-encrypted HTTP traffic just so that it can redirect users to the encrypted version (although it’s not a totally fair comparison as these days certbot can do some of the hard work for you here).

Then I stopped the nginx service and replaced it with caddy:

sudo service nginx stop
sudo service caddy start

It worked first time, no hassle, no fuss. If I want to add another application, I can spin it up in docker, add a CNAME domain record for it, add a 3 line configuration in my Caddyfile and restart the server.