Authentik SSO + homepage naked domain

Auth layer (Authentik 2026.8.0):
- compose: 3-service stack (authentik-postgres, authentik-server, authentik-worker),
  postgres health-gated, bind mounts under /home/dank/authentik
- Caddyfile: auth.franksdank.cloud vhost; forward_auth on the no-auth vhosts
  (homepage, SearXNG, Hermes, Prometheus, RomM, Copyparty); outpost path
  proxied first in a route block
- .env.example: AUTHENTIK_PG_PASS + AUTHENTIK_SECRET_KEY
- deploy.sh: render only CADDY_BASICAUTH_HASH (the homepage per-user hashes
  are retired; grafana + pihole keep basicauth)
- tests/authentik.bats (new) + updated homepage/caddyfile/pihole seams
- docs: Authentik.md + per-service pages; Caddy.md + Homepage.md updated

Homepage (naked domain):
- Caddyfile: dankclaw.franksdank.cloud -> franksdank.cloud www.franksdank.cloud;
  dankclaw + dankserver redirect to it; bare-IP catch-all updated
- addn-hosts: A records for the naked domain, www, and auth (all -> 143)
- tests/pihole.bats: vhost_names handles multi-address blocks; TLD check
  allows the naked domain

All 146 tests pass.
This commit is contained in:
Frank committed 2026-08-24 23:48:27 -07:00
1 parent 7ba1acdbc5
commit 3cc99d81cc
17 files changed
+634 -137

No files matched your search

+93 -55
View File
@@ -11,16 +11,19 @@
# (dankclaw/pihole/addn-hosts — every name resolves to 192.168.0.143)
# and handed to LAN clients by the SURFboard G36 router.
#
# The basicauth hash below 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.
# 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 wildcard
# (dns-01) via the global acme_dns block below, using the Porkbun module
# built into the franksdank/caddy-porkbun image (caddy/Containerfile).
# That needs no inbound ports and works from the LAN, where dnsmasq
# resolves these names to 192.168.0.143.
# 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
@@ -41,51 +44,61 @@
# --- Bare-IP access (health checks, convenience) ---
:80 {
redir https://dankclaw.franksdank.cloud/ 302
redir https://franksdank.cloud/ 302
}
# --- Homepage (password protected) ---
dankclaw.franksdank.cloud {
# --- Homepage (Authentik SSO) ---
franksdank.cloud www.franksdank.cloud {
root * /srv/homepage
# Operator-only admin page (Q19). Auth is checked on the original path,
# before any rewrite, so the path matcher is reliable. Caddy sorts a
# top-level 'rewrite' before 'basicauth'; that would change the path and
# break the path-based auth matchers. 'handle' preserves order.
handle /admin* {
basicauth {
frank REPLACE_WITH_ADMIN_HASH
}
try_files /admin.html
file_server
}
route {
# Authentik outpost (login UI + session management).
reverse_proxy /outpost.goauthentik.io/* authentik-server:9000
# Shared data + assets: the family OR the operator, so both pages can load
# them (the browser reuses the page's credential for these fetches). A
# 'handle' inline matcher is a single token, so the multi-path match is a
# named matcher.
@data path /services.json /status.json /app.js /style.css /deployed.js
handle @data {
basicauth {
dankuser REPLACE_WITH_HOMEPAGE_HASH
frank REPLACE_WITH_ADMIN_HASH
# 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
}
file_server
}
# Everything else (the user page): the homepage login (dankuser).
handle {
basicauth {
dankuser REPLACE_WITH_HOMEPAGE_HASH
# 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
}
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://dankclaw.franksdank.cloud/ 302
redir https://franksdank.cloud/ 302
}
# --- Authentik (SSO / OIDC provider) ---
auth.franksdank.cloud {
reverse_proxy authentik-server:9000
}
# ═══════════════════════════════════════════════════════════════
@@ -94,10 +107,15 @@ dankserver.franksdank.cloud {
# --- SearXNG (quadlet; behind the Gluetun tunnel, published 8081) ---
search.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
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
}
reverse_proxy 192.168.0.143:8081
}
# --- ComfyUI ---
@@ -112,10 +130,15 @@ chat.franksdank.cloud {
# --- Hermes ---
hermes.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
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
}
reverse_proxy hermes:8090
}
# --- Gitea (quadlet; published 3000) ---
@@ -133,10 +156,15 @@ grafana.franksdank.cloud {
# --- Prometheus ---
prometheus.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
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
}
reverse_proxy prometheus:9090
}
# --- Loki ---
@@ -176,18 +204,28 @@ books.franksdank.cloud {
# --- RomM ---
romm.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
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
}
reverse_proxy 192.168.0.235:8085
}
# --- Copyparty ---
files.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
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
}
reverse_proxy 192.168.0.235:3923
}
# --- Jellyfin ---