I have a few docker services deployed on a Beelink mini PC at home that I usually access from my LAN. Because all services are deployed in the same machine, they are listening to different ports (say 3000, 5000, 8080, etc), but that’s ugly and not friendly for other non-tech people at home that also use them, so I set up caddy as a reverse proxy. This not only allows me to provide an easy to remember URL like myservice.home.arpa, but also ensures we can use TLS secured connections with HTTPS. In today’s article, I would explain how did I achieve this at home. Let’s dive in!
Installing Caddy
First, we need to install caddy. For that, it’s better that you follow the official instructions for your system, that also will be more up to date than this article in case something change. In my case, I’m using Debian 13 Trixie, so at the time of writing all I did was:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl gnupg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddyObtaining and storing the certificates for TLS/HTTPS
Now caddy is installed, but prior to start using it with TLS encryption, we need to plan how to manage the certificates we’ll use for that. First thing we need is to know the domain we’ll use to connect to the service, and once we have that clear, we have two main options:
You could use Let’s Encrypt and ACME challenges to automatically obtain and renew trusted certificates. For that, the domain you’ll use must be a public one (you own and use a domain bought at a register), and ports 80 and 443 must be open externally, plus other basic requirements explained in Caddy official documentation for automatic HTTPS.
If you like me, are using local domains such as
myservice.home.arpaand only accessing them from your LAN, your best option is to use a self-signed certificate. Caddy already generates one while installing, but to better control it and to simplify the management of multiple services you might have in your homelab, I recommend you to generate your own using your own CA. I have an article about it that covers the topic in better detail. One advantage of using your own CA instead of the default certificate generated by Caddy is that once trusted in your devices, it doesn’t matter what/where else you deploy (a kubernetes cluster, something from a Synology, whatever in another server or a Raspberry PI, etc), they will be always be trusted. For this tutorial, I will use my own self-signed certificated obtained from my own CA in the way I explain in that article.
So continuing with the manual, self-signed generated certificate files. You should have a public certificate (e.g. myservice.crt) and its private key or secret (e.g. myservice.key). Now, let’s install them so we can use them we caddy. We’ll copy them into the /etc/caddy/certs/ folder (create it if it doesn’t exist), then, provide them with the correct file permissions.
sudo chmod 644 /etc/caddy/certs/myservice.crt
sudo chmod 600 /etc/caddy/certs/myservice.key
sudo chown -R caddy:caddy /etc/caddy/certs/*With the above commands we are indicating those files belong to the caddy user, created automatically as part of the installation process done by caddy. This is the user that will execute our caddy server. Also, for better security, we are indicating that the certificate private key is only accessible by that user caddy. Once this is done, we can proceed with the final configuration for the reverse proxy.
Configuring the reverse proxy setting up TLS/HTTPS
Most, if not all, of caddy configuration is made on its main configuration file under /etc/caddy/Caddyfile. Setting up a reverse proxy with Caddy is fairly simple. For example, imagine I want to configure a reverse proxy for the service myservice under the URL myservice.home.arpa using TLS with the previous certificates to achieve an HTTPS connection. The service is running on that same machine on docker and listening to port 8000 All I need to do is to add the following to the Caddyfile
myservice.home.arpa {
tls /etc/caddy/certs/myservice.crt /etc/caddy/certs/myservice.key
reverse_proxy http://localhost:8000 {
header_down Referrer-Policy "strict-origin-when-cross-origin"
}
}And that’s it. Now, the final thing you need to do is to restart caddy to start using the new configuration, which you can do in Debian with sudo systemctl restart caddy. Once caddy restarts, you reverse proxy should be working and you should be able to access your service under https://myservice.home.arpa from your LAN. Things are easy with caddy, right?
Note that, because in this tutorial I used a local domain (.home.arpa), in order to access that URL from your device, you need to configure the DNS for it. Otherwise, if trying to access it from your browser you will get a DNS_PROBE_POSSIBLE error. Similar DNS errors will occur if trying to access it via CLI or programmatically. Explaining how to proper configure DNS is outside of the scope of this article, as it’s not related with caddy nor its reverse proxy capabilities. On a future article, I’ll explain how to achieve this network-wide for your entire LAN with a custom DNS server like pihole. A simpler approach, but that needs to be configure on each client device, is to just update your hosts file (usually under /etc/hosts in UNIX like systems), adding at the bottom the static IP of your server (where caddy is running) and the domain used for your service, like this:
# Caddy is running on my Beelink Mini PC with static IP 192.168.1.100
192.168.1.100 myservice.home.arpa

