# Homelab Caddyfile — the single Caddy for both hosts.
#
# Caddy runs as a container on dankclaw (192.168.0.143, this repo's
# compose.yaml service 'caddy') and fronts every service on both hosts:
#   - dankclaw services: by container name (compose network) or by the
#     published LAN port (quadlet services on isolated networks)
#   - dankserver services (192.168.0.235): by published LAN port
#
# Naming: flat franksdank.cloud scheme (see docs/Infrastructure/LAN-DNS.md).
# DNS for these names is served by the Pi-hole quadlet on this host
# (dankclaw/pihole/addn-hosts — every name resolves to 192.168.0.143)
# and handed to LAN clients by the SURFboard G36 router.
#
# Authentication: Caddy forward_auth (Authentik SSO) protects the vhosts that
# do not have their own application-level auth (homepage, SearXNG, Hermes,
# Prometheus, RomM, Copyparty). The basicauth hash is a placeholder; deploy.sh
# renders the real hash (CADDY_BASICAUTH_HASH from the host .env, git-ignored)
# into /home/dank/Containers/caddy/Caddyfile, which the container mounts.
# Apps with their own auth (Grafana, Gitea, OpenWebUI, Jellyfin, *arr, Pi-hole)
# are not wrapped in forward_auth — they handle their own login.
#
# TLS: real Let's Encrypt certs. Site addresses carry no http:// prefix,
# so Caddy serves HTTPS (and auto-redirects HTTP). Certs are issued via
# dns-01 through the Porkbun module built into the franksdank/caddy-porkbun
# image (caddy/Containerfile). That needs no inbound ports and works from the
# LAN, where Pi-hole resolves these names to 192.168.0.143.

{
	# Admin stays ON: it binds to 127.0.0.1:2019 inside the container and the
	# port is not published, so nothing outside the container can reach it.
	# It powers the config file watcher, so a rendered Caddyfile change
	# hot-reloads without a container restart. 'admin off' once left a broken
	# basicauth hash sitting on disk unapplied for hours (2026-08-22).
	email admin@franksdank.cloud

	# Solve ACME challenges for every site via Porkbun DNS (no port 80/443
	# reachability needed). Credentials come from the container environment
	# (compose.yaml, from the host .env — never committed).
	acme_dns porkbun {
		api_key {env.PORKBUN_API_KEY}
		api_secret_key {env.PORKBUN_API_SECRET_KEY}
	}
}

# --- Bare-IP access (health checks, convenience) ---
:80 {
	redir https://franksdank.cloud/ 302
}

# --- Homepage (Authentik SSO) ---
franksdank.cloud www.franksdank.cloud {
	root * /srv/homepage

	route {
		# Authentik outpost (login UI + session management).
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000

		# Forward auth: check the Authentik session before serving the page.
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}

		# Operator-only admin page. Auth is checked on the original path,
		# before any rewrite, so the path matcher is reliable. 'handle'
		# preserves order.
		handle /admin* {
			try_files /admin.html
			file_server
		}

		# Shared data + assets: fetched by both the user page and the admin
		# page. With forward_auth, any authenticated user can access them
		# (the browser's Authentik session covers these fetches).
		@data path /services.json /status.json /app.js /style.css /deployed.js
		handle @data {
			file_server
		}

		# Everything else (the user page).
		handle {
			try_files /index.html
			file_server
		}
	}
}

# --- Legacy name: the old homepage name redirects to the naked domain ---
dankclaw.franksdank.cloud {
	redir https://franksdank.cloud/ 302
}

# --- Legacy name: the media host has no Caddy of its own anymore ---
dankserver.franksdank.cloud {
	redir https://franksdank.cloud/ 302
}

# --- Authentik (SSO / OIDC provider) ---
auth.franksdank.cloud {
	reverse_proxy authentik-server:9000
}

# ═══════════════════════════════════════════════════════════════
# Services on this host (dankclaw, 192.168.0.143)
# ═══════════════════════════════════════════════════════════════

# --- SearXNG (quadlet; behind the Gluetun tunnel, published 8081) ---
search.franksdank.cloud {
	route {
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}
		reverse_proxy 192.168.0.143:8081
	}
}

# --- ComfyUI ---
comfyui.franksdank.cloud {
	reverse_proxy comfyui:8188
}

# --- OpenWebUI (quadlet on slirp4netns; published 3005) ---
chat.franksdank.cloud {
	reverse_proxy 192.168.0.143:3005
}

# --- Hermes ---
hermes.franksdank.cloud {
	route {
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}
		reverse_proxy hermes:8090
	}
}

# --- Gitea (quadlet; published 3000) ---
gitea.franksdank.cloud {
	reverse_proxy 192.168.0.143:3000
}

# --- Grafana ---
grafana.franksdank.cloud {
	basicauth {
		dankuser REPLACE_WITH_HASH
	}
	reverse_proxy grafana:3000
}

# --- Prometheus ---
prometheus.franksdank.cloud {
	route {
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}
		reverse_proxy prometheus:9090
	}
}

# --- Loki ---
loki.franksdank.cloud {
	reverse_proxy loki:3100
}

# --- Pi-hole (quadlet on slirp4netns; published 8083) ---
pihole.franksdank.cloud {
	basicauth {
		dankuser REPLACE_WITH_HASH
	}
	reverse_proxy 192.168.0.143:8083
}

# ═══════════════════════════════════════════════════════════════
# Services on dankserver (192.168.0.235) — published LAN ports
# ═══════════════════════════════════════════════════════════════

# --- Plex (existing, kept) ---
# http:// on purpose: franksdank.casa is not hosted in the same Porkbun
# account as franksdank.cloud, so the DNS-01 provider cannot issue a
# Let's Encrypt cert for it. It stays plain-HTTP legacy; the canonical
# name is plex.franksdank.cloud (HTTPS, below).
http://plex.franksdank.casa {
	reverse_proxy 192.168.0.235:32400
}

plex.franksdank.cloud {
	reverse_proxy 192.168.0.235:32400
}

# --- Calibre-Web ---
books.franksdank.cloud {
	reverse_proxy 192.168.0.235:8083
}

# --- RomM ---
romm.franksdank.cloud {
	route {
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}
		reverse_proxy 192.168.0.235:8085
	}
}

# --- Copyparty ---
files.franksdank.cloud {
	route {
		reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
		forward_auth authentik-server:9000 {
			uri /outpost.goauthentik.io/auth/caddy
			copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Name
			trusted_proxies private_ranges
		}
		reverse_proxy 192.168.0.235:3923
	}
}

# --- Jellyfin ---
jellyfin.franksdank.cloud {
	reverse_proxy 192.168.0.235:8096 {
		transport http {
			versions h2c 1.1
		}
	}
}

# --- *arr Stack ---
radarr.franksdank.cloud {
	reverse_proxy 192.168.0.235:7878
}

sonarr.franksdank.cloud {
	reverse_proxy 192.168.0.235:8989
}

lidarr.franksdank.cloud {
	reverse_proxy 192.168.0.235:8686
}

readarr.franksdank.cloud {
	reverse_proxy 192.168.0.235:8787
}

prowlarr.franksdank.cloud {
	reverse_proxy 192.168.0.235:9696
}

qbittorrent.franksdank.cloud {
	reverse_proxy 192.168.0.235:8080
}

# --- Optional: Jackett ---
# jackett.franksdank.cloud {
# 	reverse_proxy 192.168.0.235:9117
# }

# --- Optional: Whisparr ---
# whisparr.franksdank.cloud {
# 	reverse_proxy 192.168.0.235:6969
# }
