pez-infra/ansible/services/caddy
Rasmus "Pez" Wejlgaard abb283c1d7
terraform plan on pr and caddy metrics on localhost since we have all… (#96)
* terraform plan on pr and caddy metrics on localhost since we have alloy now

* remove refreshing state
2026-05-05 13:35:37 +01:00
..
Caddyfile terraform plan on pr and caddy metrics on localhost since we have all… (#96) 2026-05-05 13:35:37 +01:00
README.md Grafana Cloud Migration (#94) 2026-05-04 13:40:30 +01:00

Caddy

Reverse proxy and TLS termination for all homelab services. Runs on helsinki-a (100.67.6.27) as a system service (not Docker).

Replaces the standalone pez-proxy repo.

Structure

services/caddy/
├── Caddyfile           # Live config captured from helsinki-a
├── Caddyfile.template  # Templatized version with variable placeholders
└── README.md

How It Works

Helsinki-a sits behind Cloudflare DNS and acts as the single entry point for all *.pez.sh and *.pez.solutions traffic. Caddy handles automatic TLS via Let's Encrypt/ZeroSSL, then reverse-proxies to backend services over the Tailscale mesh.

Traffic Flow

Internet → Cloudflare → helsinki-a (Caddy) → Tailscale → backend host:port

Admin API

Caddy's admin API listens on 100.67.6.27:2019 (Tailscale-only, not publicly exposed). Useful for config reloads without downtime:

caddy reload --config /etc/caddy/Caddyfile
# or via API:
curl http://100.67.6.27:2019/config/

Metrics

Caddy exposes Prometheus metrics with per_host granularity. Scraped by Prometheus on london-a.

Authelia Forward Auth Pattern

Most admin-facing services are protected by Authelia SSO. Authelia runs on helsinki-a itself (localhost:9091) alongside an LLDAP directory and MariaDB backend (see services/authelia/).

How forward_auth Works

Caddy's forward_auth directive intercepts every request before it reaches the upstream. It sends a subrequest to Authelia's verification endpoint:

forward_auth localhost:9091 {
    uri /api/authz/forward-auth
    copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}

Flow:

  1. Client requests https://grafana.pez.sh/some/page
  2. Caddy sends a verification subrequest to localhost:9091/api/authz/forward-auth
  3. Authelia checks the session cookie:
    • Valid session → returns 200; Caddy copies identity headers (Remote-User, Remote-Groups, Remote-Name, Remote-Email) and forwards to the upstream
    • No/expired session → returns 401 with redirect; Caddy sends user to auth.pez.sh to log in via Authelia's portal
  4. After login, Authelia sets a session cookie and redirects back to the original URL

Which Services Use Authelia

Service Auth Reason
Radarr, Sonarr, Lidarr, Readarr Authelia Media management
Prowlarr, Transmission (download) Authelia Download tools
slskd (Soulseek) Authelia P2P client
Miniflux (RSS) Authelia RSS reader
Apps dashboard Authelia Internal apps page
Jellyfin, Plex Own auth Have built-in user management
Overseerr, Jellyseerr Own auth Have built-in user management
Navidrome (music) No auth* Accessible directly
Bitwarden Own auth Has built-in vault auth
Forgejo (git) Own auth Has built-in user management
Authelia portal N/A Is the auth system itself
LLDAP web UI N/A Admin directory management

Template Snippet

The template file uses a Caddy snippet to DRY up the auth block:

(authelia) {
    forward_auth localhost:{{AUTHELIA_PORT}} {
        uri /api/authz/forward-auth
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    }
}

Usage in a site block: import authelia

Template Variables

The Caddyfile.template replaces hardcoded values with placeholders:

Variable Current Value Description
{{HELSINKI_A_IP}} 100.67.6.27 helsinki-a Tailscale IP
{{LONDON_A_IP}} 100.122.219.41 london-a Tailscale IP
{{LONDON_B_IP}} 100.84.65.101 london-b Tailscale IP
{{AUTHELIA_PORT}} 9091 Authelia verification port
{{DOMAIN_PRIMARY}} pez.sh Primary domain
{{DOMAIN_ALT}} pez.solutions Alternate domain

Notes

  • The live Caddyfile on helsinki-a is at /etc/caddy/Caddyfile
  • Caddy auto-provisions TLS certificates for all listed domains
  • Static sites (pez.sh, pez.solutions, etc.) are served from /srv/ on helsinki-a