fix(caddy,authentik): auth guarded vhosts by proxying the whole request through authentik
The forward_auth target /outpost.goauthentik.io/auth/caddy does not exist in authentik 2026.8 (verified live: 404 for every header combination; the URL tree has no outpost auth prefix at all — the outpost worker dials back to core over ws/outpost/<uuid>/ instead). Unauthenticated subrequests got 404, Caddy treated >=400 as 'not authenticated' and redirected browsers to the dead path — users saw authentik's own Not-Found page. Fix: guarded vhosts now proxy the whole request through authentik-server:9000 with X-authentik-meta-outpost/-provider/-app headers (the exact header set this build's Traefik controller emits, adapted for Caddy). Unauthenticated clients get the login flow served in place; once a session exists, authentik proxies on to the provider's internal_host — now http://caddy:8017, a new post-auth internal listener that routes straight to the app. The chain terminates; nothing dials back into authentik. Live DB changes applied alongside (postgres is the source of truth): provider pk=1 authentication_flow=default-authentication-flow (was NULL — the actual cause of the 404s) and internal_host=http://caddy:8017 (was self-referential http://authentik-server:9000).
This commit is contained in:
1 parent
3a16375cfe
commit
ef07e7d01a
5 files changed
+153
-141
No files matched your search
+90
-74
@@ -11,12 +11,17 @@
|
||||
# (dankclaw/pihole/addn-hosts — every name resolves to 192.168.0.143)
|
||||
# and handed to LAN clients by the SURFboard G36 router.
|
||||
#
|
||||
# Authentication chain (Anubis rollout, 2026-08-28): the guarded vhosts
|
||||
# (homepage, SearXNG, Hermes, Prometheus, RomM, Copyparty) proxy EVERYTHING
|
||||
# through the Anubis bot-challenge proxy first. Chain: client → Caddy (TLS,
|
||||
# public listener) → Anubis :8923 (verify: DENY known AI scrapers, CHALLENGE
|
||||
# everyone else) → Caddy's internal listener http://:8016 (Authentik
|
||||
# forward_auth + app routing resumes; Host headers survive both hops) → app.
|
||||
# Authentication chain (2026-08-29): the guarded vhosts (homepage, SearXNG,
|
||||
# Hermes, Prometheus, RomM, Copyparty) proxy EVERYTHING through the Anubis
|
||||
# bot-challenge proxy first, then the whole request is proxied THROUGH
|
||||
# Authentik (2026.8 proxy-provider mode: this build serves no forward_auth
|
||||
# endpoint; the authentication flow runs inline — unauthenticated clients get
|
||||
# the login UI served in place, and once a session exists Authentik proxies
|
||||
# the request on to the app via the provider's internal_host). Chain: client →
|
||||
# Caddy (TLS, public listener) → Anubis :8923 (verify: DENY known AI scrapers,
|
||||
# CHALLENGE everyone else) → Caddy's internal listener http://:8016 (auth
|
||||
# decision; Host headers survive every hop) → authenticated traffic is
|
||||
# forwarded back to http://:8017 and routed straight to the app.
|
||||
# Apps with their own auth (Grafana, Gitea, OpenWebUI, ComfyUI, Jellyfin,
|
||||
# *arr, Pi-hole) and the Authentik IdP itself (auth.franksdank.cloud — its
|
||||
# login flow must never sit behind a challenge) are exempt by construction:
|
||||
@@ -224,104 +229,115 @@ prowlarr.franksdank.cloud {
|
||||
qbittorrent.franksdank.cloud {
|
||||
reverse_proxy 192.168.0.235:8080
|
||||
}
|
||||
|
||||
# --- Internal listener: where Anubis forwards accepted traffic ---
|
||||
# --- Internal listener: auth decision layer -------------------------------
|
||||
# Anubis dials http://caddy:8016 after verifying a client (TARGET in
|
||||
# dankclaw/anubis/quadlet/anubis.container). Host headers survive the hop,
|
||||
# so per-vhost routing resumes here: outpost paths go straight to the
|
||||
# Authentik outpost, everything else runs the forward_auth check and then
|
||||
# dials the app. This block is the second half of every guarded vhost.
|
||||
# dankclaw/anubis/quadlet/anubis.container). Host headers survive the hop, so
|
||||
# per-vhost routing resumes here: guarded vhosts proxy the WHOLE request
|
||||
# through Authentik (the meta headers tell Authentik which outpost, provider
|
||||
# and app are answering); unauthenticated clients get the login flow served
|
||||
# in place, authenticated traffic is forwarded back to http://:8017 and
|
||||
# routed straight to the app. Exempt vhosts never enter this block.
|
||||
http://:8016 {
|
||||
@home host franksdank.cloud www.franksdank.cloud
|
||||
handle @home {
|
||||
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
|
||||
}
|
||||
reverse_proxy authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
|
||||
@search host search.franksdank.cloud
|
||||
handle @search {
|
||||
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 authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
|
||||
@hermes host hermes.franksdank.cloud
|
||||
handle @hermes {
|
||||
reverse_proxy authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
|
||||
@prometheus host prometheus.franksdank.cloud
|
||||
handle @prometheus {
|
||||
reverse_proxy authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
|
||||
@romm host romm.franksdank.cloud
|
||||
handle @romm {
|
||||
reverse_proxy authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
|
||||
@files host files.franksdank.cloud
|
||||
handle @files {
|
||||
reverse_proxy authentik-server:9000 {
|
||||
header_up X-authentik-meta-outpost 7e39655b-58d3-4fe6-a80a-513f31051217
|
||||
header_up X-authentik-meta-provider 1
|
||||
header_up X-authentik-meta-app name=caddy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Post-auth listener: where Authentik forwards authenticated traffic ----
|
||||
# The proxy provider's internal_host is http://caddy:8017, so every request
|
||||
# that passes authentication lands here (Host header preserved) and routes
|
||||
# straight to its app. This is the end of the chain — nothing dials back
|
||||
# into Authentik from here, so the chain cannot loop.
|
||||
http://:8017 {
|
||||
@home host franksdank.cloud www.franksdank.cloud
|
||||
handle @home {
|
||||
root * /srv/homepage
|
||||
handle /admin* {
|
||||
try_files /admin.html
|
||||
file_server
|
||||
}
|
||||
@data path /services.json /status.json /app.js /style.css /deployed.js
|
||||
handle @data {
|
||||
file_server
|
||||
}
|
||||
handle {
|
||||
try_files /index.html
|
||||
file_server
|
||||
}
|
||||
}
|
||||
|
||||
@search host search.franksdank.cloud
|
||||
handle @search {
|
||||
reverse_proxy 192.168.0.143:8081
|
||||
}
|
||||
|
||||
@hermes host hermes.franksdank.cloud
|
||||
handle @hermes {
|
||||
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
|
||||
}
|
||||
|
||||
@prometheus host prometheus.franksdank.cloud
|
||||
handle @prometheus {
|
||||
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
|
||||
}
|
||||
|
||||
@romm host romm.franksdank.cloud
|
||||
handle @romm {
|
||||
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
|
||||
}
|
||||
|
||||
@files host files.franksdank.cloud
|
||||
handle @files {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user