Reverse Proxy (Caddy)
Demi can set up Caddy as a reverse proxy so you can access services by domain name with automatic HTTPS instead of remembering IP addresses and port numbers.
Why a Reverse Proxy?
Without a reverse proxy:
- http://192.168.1.50:8096 for Jellyfin
- http://192.168.1.50:8080 for Nextcloud
- http://192.168.1.50:9000 for Nginx
With Caddy:
- https://media.home.local for Jellyfin
- https://cloud.home.local for Nextcloud
- https://www.home.local for Nginx
One entry point, memorable names, and HTTPS.
Setting It Up
You: I want to access my services by domain name
Demi: I'll set up Caddy as a reverse proxy. Here's the plan:
- Deploy Caddy on ports 80/443
- Volume: /srv/caddy/Caddyfile, /srv/caddy/data, /srv/caddy/config
- Firewall: open 80, 443
- Create initial Caddyfile with your existing services
What domain pattern do you want? (e.g. *.home.local, *.homelab)
You: use *.home.local
Demi: Plan:
- media.home.local -> jellyfin:8096
- cloud.home.local -> nextcloud:80
- www.home.local -> nginx:80
- Remove direct port mappings from services
Ready to proceed?
Adding a Service to Caddy
After Caddy is running, adding a new service is simple:
You: deploy grafana and put it behind caddy at graphs.home.local
Demi: Plan:
- Deploy grafana (no direct port mapping)
- Add to Caddyfile: graphs.home.local -> grafana:3000
- Restart Caddy
Ready to proceed?
Local vs Public Domains
Local domains (.home.local, .homelab, *.lan):
- Work inside your network only
- Plain HTTP by default (no browser warnings about self-signed certs)
- You'll need to add DNS entries (via Pi-hole, your router, or /etc/hosts on your devices)
- If you want HTTPS locally, Caddy will use self-signed certs (browsers will warn)
Public domains (yourdomain.com):
- Caddy handles Let's Encrypt certificates automatically
- Your router needs port 80/443 forwarded to the homelab
- Caddy validates domain ownership and provisions real HTTPS certs
DNS Setup
For local domains, you need your devices to resolve *.home.local to your homelab IP. Options:
- Pi-hole/AdGuard: Add local DNS records pointing *.home.local to your server
- Router DNS: Some routers let you add custom DNS entries
- /etc/hosts: Manual entry on each device (least convenient)
You: I have pi-hole running, add DNS for my services
Demi: ★ container (action=exec, name=pihole,
command=pihole -a addcustomdns media.home.local 192.168.1.50)
★ container (action=exec, name=pihole,
command=pihole -a addcustomdns cloud.home.local 192.168.1.50)
DNS entries added.
Caddyfile Format
The Caddyfile lives at /srv/caddy/Caddyfile. Each service gets a block:
# Local domains use http:// prefix (no self-signed cert hassle)
http://media.home.local {
reverse_proxy jellyfin:8096
}
http://cloud.home.local {
reverse_proxy nextcloud:80
}
# Public domain (Caddy handles Let's Encrypt automatically)
cloud.example.com {
reverse_proxy nextcloud:80
}
# With custom headers
http://git.home.local {
reverse_proxy gitea:3000
header {
X-Frame-Options SAMEORIGIN
}
}
Caddy automatically handles HTTPS, HTTP/2, and certificate renewal.
Security
Services behind Caddy should not expose their ports directly to the host. They only need to be reachable on the nurvus Podman network, which Caddy is also on. This means:
- Services are only accessible through Caddy (not by IP:port)
- Caddy enforces HTTPS
- Only ports 80 and 443 need to be open in the firewall