Reverse Proxy & Traffic Routing
Centralized traffic management is handled by Caddy. Caddy was chosen over Nginx or Traefik for its native, automatic HTTPS provisioning and its highly readable configuration syntax.
Automated Wildcard TLS (Cloudflare DNS-01)
To keep internal service names completely private, the infrastructure does not use HTTP-01 ACME challenges. Instead, it uses DNS-01 challenges via the Cloudflare API.
This allows Caddy to provision a wildcard certificate (*.potterman.party) without exposing the internal IP addresses or service names to public Certificate Transparency logs.
The Caddyfile Template
In keeping with GitOps principles, the proxy configuration is managed as a Jinja2 template (Caddyfile.j2). Ansible dynamically populates the routing targets using the zerotier_ip variables assigned to each host in the inventory.
Here is the live Caddyfile template powering the infrastructure:
# templates/Caddyfile.j2
{
log {
level warn
}
http_port 80
https_port 443
}
# Desec DNS-01 Challenge Snippet
(desec_tls) {
tls {
dns desec {
token {env.DESEC_API_TOKEN}
}
}
}
# Wildcard cert
*.potterman.party {
import desec_tls
abort
}
# Infrastructure
proxmox.potterman.party {
import desec_tls
# PVE ZT IP
reverse_proxy {{ hostvars['pve']['zerotier_ip'] }}:8006 {
transport http {
tls_insecure_skip_verify
}
}
}
pbs.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['pve']['zerotier_ip'] }}:8007 {
transport http {
tls_insecure_skip_verify
}
}
}
forgejo.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:3000
}
# Pihole | DNS Adblock
pihole.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:800
}
# The Arr Stack & Media
sonarr.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:8989
}
radarr.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:7878
}
prowlarr.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:9696
}
decypharr.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:8282
}
sabnzbd.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:8585
}
jellyfin.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:8096
}
jellyseer.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:5055
}
# Dashboard
home.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:3005
}
foundry.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:30000
}
pelican.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:80
}
# Identity Provider (SSO)
auth.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:9000
}
# S3 Object Storage (Garage on K3s)
s3.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['k3s-node1']['zerotier_ip'] }}:30900
}
paperless.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:{{ app_services.paperless.internal_port }}
}
wings.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['pve-wings-vm-01']['zerotier_ip'] }}:8080
}
# Cloudforge Academy
grafana.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:3001
}
prometheus.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:9090
}
alertmanager.potterman.party {
import desec_tls
reverse_proxy {{ hostvars['debian-docker']['zerotier_ip'] }}:9093
}
View the Caddy Ansible Role on GitHub
Current Routing Targets
Caddy routes traffic to services across three host types:
- Proxmox Host (
pve): Proxmox Web UI, PBS Web UI - Docker VM (
debian-docker): Forgejo, Pi-hole, Sonarr, Radarr, Prowlarr, Jellyfin, Jellyseerr, Homepage, Authentik, Firefly III, FoundryVTT, and the Arr media stack - IONOS VPS (
ionos_vps): hoodik cloud storage - K3s Node (
k3s-node1): Garage S3 object storage (via NodePort 30900)
Zero Downtime Reloads
When Ansible updates the Caddyfile, it utilizes systemd handlers to perform a graceful reload of the Caddy service. Active connections are maintained while the new routing rules are applied.