feat(3083): the gateway serves authelia

authelia has listened on 127.0.0.1:9091 since it was stood up, with
nothing proxying to it — so `auth.<swarm.domain>` resolved and then
refused the connection. This is the vhost that was never written.

Follows forge and matrix exactly: one `optionalAttrs` attrset merged into
`virtualHosts`, TLS chosen by `vhostTlsFor` (the swarm-services leaf
already names it, since `swarm.serviceDomains` includes
`authelia.domain`), and the same four wiring sites those two occupy —
vhost, dnsmasq address, local-dev `/etc/hosts`, and the arg lists that
feed both files.

Gated on this host running the container, not on authelia being
configured: every hive knows the swarm's `authelia.url`, but only the one
serving it may claim the name. A client hive declaring this vhost would
answer for a service it does not run.

Two things that are deliberate rather than incidental:

`X-Forwarded-{Proto,Host,Uri,For}` are set because authelia decides by
the *original* request — the login redirect and the session cookie's
domain both derive from them. Without them every request looks like it
arrived at 127.0.0.1 over plain http.

And no `auth_basic`. Applying the gateway's basic-auth block to the SSO
provider would put the login page behind the login mechanism it exists to
replace.
This commit is contained in:
atlas 2026-08-11 22:32:26 +02:00 committed by mara
commit 67a20d387f
3 changed files with 45 additions and 1 deletions

View file

@ -9,6 +9,7 @@
cfg, # services.hyperhive.gateway
forgeCfg,
matrixCfg,
autheliaCfg, # services.hyperhive.swarm.authelia
hyperhiveDomain,
dashboardDist,
swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css
@ -123,6 +124,42 @@ let
};
};
# Authelia sub-domain vhost. `server_name = authelia.domain`, all of
# `/` → authelia. Empty attrset unless THIS host runs the container:
# every hive knows the swarm's `authelia.url`, but only the one
# serving it may claim the name — a client hive declaring this vhost
# would answer for a service it does not run.
#
# ⚠️ The server name must be exactly `autheliaCfg.domain`, not a
# near-miss: authelia validates `authelia_url ⊂ session cookie domain`
# at STARTUP, so a mismatch is a container that refuses to boot rather
# than a login that misbehaves.
#
# ⚠️ And deliberately NO `dashboardAuth` here. That block is the
# gateway's `auth_basic`; applying it to the SSO provider would put
# the login page behind the login mechanism it exists to replace.
autheliaVhost = lib.optionalAttrs autheliaCfg.enable {
"${autheliaCfg.domain}" = (vhostTlsFor autheliaCfg.domain) // {
listen = vhostListen;
extraConfig = securityHeaders;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString autheliaCfg.port}/";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
# authelia decides by the ORIGINAL request, not by the hop it
# sees — the login redirect and the session cookie's domain
# both derive from these. Without them every request looks
# like it arrived at 127.0.0.1 over plain http.
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
'';
};
};
};
# Matrix sub-domain vhost. `server_name = matrixCfg.gatewayHost`.
# `/_matrix/*` → tuwunel (CORS *, 50M body cap, 1h long-poll
# timeout). `/` serves fluffychat or 404 if GUI off. nginx
@ -409,5 +446,6 @@ in
};
}
// forgeVhost
// autheliaVhost
// matrixVhost;
}