Homelab from Zero #8: Clean internal HTTPS with CaddyHomelab from Zero #8: Clean internal HTTPS with Caddy

Homelab from Zero #8: Clean internal HTTPS with Caddy

This is part 8 of Homelab from Zero. In part 7 you learned what a reverse proxy is and why your lab wants one. Today we install one (Caddy) and use it to turn http://192.168.1.73:8080 into a clean https://heimdall.home with a green padlock and no browser warning.

What we’re building

Right now every service lives at an IP and a port. By the end of this post:

Before After
http://192.168.1.73:8080 https://heimdall.home
http://192.168.1.73:8081/admin https://pihole.home
http://192.168.1.73:3001 https://uptime.home

Caddy sits in front of everything, terminates HTTPS, and routes each hostname to the right service. The certificates are issued and renewed automatically.

Step 1: Run Caddy

Caddy needs ports 80 and 443, so run it in a container that owns them:

docker run -d \
--name caddy \
-p 80:80 \
-p 443:443 \
-v ~/caddy/Caddyfile:/etc/caddy/Caddyfile \
-v ~/caddy/data:/data \
--restart unless-stopped \
caddy:2
Piece Plain English
-p 80:80 -p 443:443 The standard web ports: Caddy owns them
-v ~/caddy/Caddyfile:... Your config file (we write it next)
-v ~/caddy/data:/data Keeps the certificates across restarts

Step 2: Write the Caddyfile

A Caddyfile is Caddy’s config, one block per hostname. Create ~/caddy/Caddyfile:

Caddyfile
# Internal-only TLS. Caddy issues certs from its own local CA.
*.home {
tls internal
@heimdall host heimdall.home
handle @heimdall {
reverse_proxy 192.168.1.73:8080
}
@pihole host pihole.home
handle @pihole {
reverse_proxy 192.168.1.73:8081
}
@uptime host uptime.home
handle @uptime {
reverse_proxy 192.168.1.73:3001
}
}

Each @name host x.home / handle pair says: “when someone asks for this hostname, forward to this service.” Reload Caddy to pick up the file:

docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Step 3: Why tls internal

On a public server you’d let Caddy fetch a real Let’s Encrypt certificate. But .home isn’t a public domain; there’s no public DNS for Let’s Encrypt to validate against. So we tell Caddy tls internal, which means Caddy runs its own private certificate authority and signs certs itself.

The catch: your devices don’t trust that private CA yet, so you’ll still see a warning until you tell them to. That’s the next step.

Step 4: Point DNS at the proxy

Your laptop needs to know that heimdall.home means “the proxy.” You’re already running Pi-hole, which makes this easy. In the Pi-hole admin page, go to Settings → Local DNS → DNS Records and add one wildcard-style entry per hostname, all pointing at the server:

heimdall.home → 192.168.1.73
pihole.home → 192.168.1.73
uptime.home → 192.168.1.73

Now when any device on the network looks up heimdall.home, Pi-hole answers with the proxy’s IP, and Caddy takes it from there.

Step 5: Trust the CA (the green padlock)

The last step removes the browser warning. Copy Caddy’s root certificate out of the container and install it on your computer:

docker cp caddy:/data/caddy/pki/authorities/local/root.crt ~/caddy-root.crt

Then add ~/caddy-root.crt to your operating system’s trust store:

  • macOS: open Keychain Access, import it, set it to “Always Trust.”
  • Windows: double-click it → Install Certificate → Local Machine → Trusted Root Certification Authorities.
  • Linux: copy to /usr/local/share/ca-certificates/ and run sudo update-ca-certificates.

Restart your browser and visit https://heimdall.home. Green padlock, no warning. Do this once per device you browse from.

Redacted on purpose: use invented hostnames like .home and never expose this CA or these services to the public internet; it’s a LAN-only setup.

The commands you’ll actually use

Command What it does
docker exec caddy caddy reload --config /etc/caddy/Caddyfile Apply Caddyfile changes
docker logs caddy What is Caddy saying? (start here if a site won’t load)
docker restart caddy Turn it off and on again

What you have now

Every service in your lab answers at a clean https://name.home address with a real green padlock, certificates issued and renewed automatically, and adding a new service is just three lines in the Caddyfile plus a DNS record. Your lab finally feels like a polished, professional setup.

In part 9 we go one step further: Tailscale, so you can reach all of this securely from anywhere (a coffee shop, your phone, another city) without opening a single port to the internet.


← Back to blog

Following along?