Skip to content

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