Post

Caddy

Reverse Proxies are great tools…

They allow you to create a central hub for traffic that can get redirected to the correct service. For example, both Jellyfin and Cockpit use a web interface. If I want to have both running on port 443, the default port for HTTPS, I’m out of luck. This means I have to type a rather messy url.to.cockpit:8443 in order to access Cockpit, and each additional service on port 443 compounds this issue. It also means I have to keep an extra port open in my firewall for every service, which increases my attack surface. I run most of my homelab on LAN, so I’m likely being overly cautious, but we strive for best practice here.

This is where Caddy steps in. Caddy uses a simple, text-based configuration called a Caddyfile. In it, you specify the URL that Caddy should expect to see and the destination that traffic should be routed to. To follow the earlier example, I can say:

  • url.to.jellyfin -> Jellyfin:8443
  • url.to.cockpit -> host.containers.internal:8444

Now, the only service that binds to port 443 is Caddy and the only port I need to open is 443. Caddy will accept traffic and forward it to the correct internal service if an entry is present. This comes with the added benefit of being more secure as well. If I receive a connection that isn’t present in my Caddyfile, such as my raw IP address, Caddy won’t send it anywhere. What’s more, with the Caddy MIB plugin, I can temporarily ban connections trying to brute-force their way to a valid connection.

Caddy has the added benefit, for those with services on the open internet, of being able to fetch and serve HTTPS certificates for you. You can use a variety of different challenges to obtain your certificate, but I’m partial to DNS-01. Once Caddy obtains your certificates, clients connecting to your service will be able to encrypt their traffic with HTTPS and won’t get the warning from their browser that the site isn’t trusted. While Caddy normally operates at the application layer (layer 7), which is the layer HTTP(S) uses, there are some services I have that have to operate at layer 4; specifically Samba and Minecraft. There’s yet another plugin for that, however! The layer 4 plugin accepts traffic on a specific port - the URL can’t be specified here - and forwards it so a service. Simple, if lacking a the niceness of being able to specify the URL, but works like a charm to keep my Samba service from binding to a privileged port.

With a reverse proxy, having an ever-expanding list of services becomes less of an issue. I have a single point of control with a text-based, versionable configuration file. Now that Caddy in place, I had a solid service base for my homelab that was highly extensible. But I was aware that, just because my services were functional, didn’t mean I had done it all the right way…

This post is licensed under CC BY 4.0 by the author.

Trending Tags