Internal HTTPS for a homelab with Caddy
This is an example of the kind of write-up I like: a small, specific problem, solved end to end, with the config you can actually copy. Names and secrets are redacted; the structure is real.
The problem
Self-signed certs mean a browser warning on every internal service. I wanted clean
https://service.home URLs with a green padlock, issued and renewed automatically, all
inside the LAN.
The setup
| Piece | Role |
|---|---|
| Reverse proxy | Caddy, terminating TLS for every service |
| DNS | Split-horizon: *.home resolves to the proxy’s LAN IP |
| Services | Plain HTTP on the backend; Caddy adds TLS in front |
The Caddyfile
# Internal-only TLS. Caddy issues certs from its own local CA and# installs the root automatically on hosts that trust it.*.home { tls internal
@dashboard host dashboard.home handle @dashboard { reverse_proxy 127.0.0.1:8080 }
@git host git.home handle @git { reverse_proxy 192.168.1.50:3000 }}Why tls internal
On a public VPS you’d let Caddy fetch a real Let’s Encrypt cert. Inside the LAN there’s no
public DNS to validate against, so tls internal tells Caddy to run its own CA. Trust the
root once per device and every .home service is green.
Redacted on purpose: real hostnames, the CA fingerprint, and any tokens. The pattern is what’s worth sharing — not my secrets.
That’s the format. Specific problem, real config, nothing leaked.
← Back to blog