From 275d5026395c6079a8bc631c8be73332b5fd6f31 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 12 Aug 2026 10:08:34 +0200 Subject: [PATCH 1/2] feat(3189): the sso vhost serves a themed page instead of a bare 502 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A dead authelia upstream almost always means "no users yet" — 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. nginx's default 502 says the opposite: it points at the proxy, which is the one component that is fine. Adds `ssoUnavailable` to the shared error-page set and wires it on the authelia vhost the same way the per-agent blocks wire `__hive_agent_unreachable`: `proxy_intercept_errors on` plus an internal location serving the static page. The page leads with the bootstrap command rather than burying it under an explanation, and names the container journal as the fallback for the cases where users are not the problem. Same Catppuccin template as its siblings, so this costs no new styling. --- nix/host-modules/hive-gateway/error-pages.nix | 18 ++++++++++++++++++ nix/host-modules/hive-gateway/vhosts.nix | 11 +++++++++++ 2 files changed, 29 insertions(+) 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..297c724f 100644 --- a/nix/host-modules/hive-gateway/vhosts.nix +++ b/nix/host-modules/hive-gateway/vhosts.nix @@ -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; ''; }; }; From ac15c68cd28710b49480888a0044f4147e63a17b Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 12 Aug 2026 10:22:06 +0200 Subject: [PATCH 2/2] docs(3189): the error-page scope text describes the new shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two claims this branch falsified and left standing, both caught in review: `vhosts.nix`'s `errorPages` param comment enumerated the set (`{ notFound, unreachable, unauthorized }`) and adding a fourth member made the enumeration wrong at the point a reader consults it. `gateway.md` said extending custom error pages beyond the per-agent routes was "a separate follow-up" — while this branch is that follow-up, so the doc contradicted the code sitting next to it. Rewrites the scope rule as the criterion rather than a list, since a list is what went stale: a route earns a page when the default status would point at the wrong component. That covers the per-agent routes and the sso vhost, and explains why forge/matrix/fluffychat still don't qualify — their upstreams being down means what the code says. --- docs/gateway.md | 14 ++++++++++---- nix/host-modules/hive-gateway/vhosts.nix | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) 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/vhosts.nix b/nix/host-modules/hive-gateway/vhosts.nix index 297c724f..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