diff --git a/docs/gateway.md b/docs/gateway.md index 544296da..b02b9752 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -477,10 +477,16 @@ palette (`#1e1e2e` bg, `#cdd6f4` text, `#cba6f7` heading). No dependencies on the frontend dist — these pages render even when hive-c0re itself is down. -Scope is intentionally narrow: only routes already special-cased in -the nginx config get custom error pages. Other gateway routes -(forge / matrix / fluffychat) get nginx defaults — extending the -custom-error pattern there is a separate follow-up. +Scope is intentionally narrow: a route earns a custom page when the +default status code would point at the wrong component. The per-agent +routes qualify (a 502 there means the harness is restarting, not that +the gateway is broken), and so does `auth.` — a dead authelia +upstream almost always means the user store was never bootstrapped, and +a bare 502 blames the proxy, which is the one part that is working. + +Forge / matrix / fluffychat still get nginx defaults: their upstreams +being down means what the status code says, so a themed page would add +styling and no information. ## HTTP Basic auth diff --git a/nix/host-modules/hive-gateway/error-pages.nix b/nix/host-modules/hive-gateway/error-pages.nix index 3285632c..f1ad62e9 100644 --- a/nix/host-modules/hive-gateway/error-pages.nix +++ b/nix/host-modules/hive-gateway/error-pages.nix @@ -56,6 +56,24 @@ in ''; }; + # Shown when the authelia vhost's upstream refuses the connection. + # Leads with the bootstrap because that is overwhelmingly the cause: + # authelia treats an empty user store as a FATAL startup error, so an + # enabled-but-unbootstrapped swarm crash-loops behind a vhost that is + # working perfectly, and the raw 502 points at the proxy instead. + ssoUnavailable = mkPage { + name = "sso-unavailable"; + title = "sso unavailable"; + accent = "#f9e2af"; + body = '' +

The swarm's identity provider isn't answering. The gateway is fine — nothing is listening behind it.

+

Most likely: no users exist yet. Authelia refuses to start with an empty user store, so it never finishes booting. Add the first account on the host running it:

+
swarmctl user add <username> \
+      --display-name <Name> --email <addr> --group admins
+

Otherwise check the container: journalctl -M swarm-authelia -u authelia-swarm. This page recovers on reload once the provider is up.

+ ''; + }; + unauthorized = mkPage { name = "unauthorized"; title = "unauthorized"; diff --git a/nix/host-modules/hive-gateway/vhosts.nix b/nix/host-modules/hive-gateway/vhosts.nix index 20d9c97d..06eb4482 100644 --- a/nix/host-modules/hive-gateway/vhosts.nix +++ b/nix/host-modules/hive-gateway/vhosts.nix @@ -13,7 +13,7 @@ hyperhiveDomain, dashboardDist, swaggerUiTheme, # nix/packages/swagger-ui-theme.nix: has index.html + hyperhive-theme.css - errorPages, # ./error-pages.nix: { notFound, unreachable, unauthorized } + errorPages, # ./error-pages.nix: { notFound, unreachable, unauthorized, ssoUnavailable } tlsCert, tlsKey, svcCert, # swarm-services leaf, for names the hive CA cannot sign @@ -155,6 +155,17 @@ let 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; + # A dead upstream here means "not bootstrapped" far more often + # than "misconfigured proxy", and a bare 502 says the opposite. + proxy_intercept_errors on; + error_page 502 503 504 = /__hive_sso_unavailable; + ''; + }; + locations."= /__hive_sso_unavailable" = { + extraConfig = '' + internal; + alias ${errorPages.ssoUnavailable}; + default_type text/html; ''; }; };