hyperhive/docs/swarm/ui.md
atlas 470d2ad845 docs(3167): the swarm UI page, and the group step that gates it
New docs/swarm/ui.md (split-page shape, per the docs rule), linked from
the swarm README and added to the gateway's vhost map.

Leads with the step that separates 'protected' from 'locked out':
swarmctl user add <you> --group operators. auth_request asks whether
there is a session; the access_control rule is what makes it mean
operator, and an account created before the rule existed has no groups.

Also records the four wiring sites a swarm service name needs, with the
certificate one called out - serviceDomains is both the sub-CA's
nameConstraints set and the leaf's SANs, and the apex is a sibling of
the other three rather than a parent, so nothing issues for it
implicitly.
2026-08-12 17:46:15 +02:00

3.3 KiB

Swarm UI

The swarm's own web surface, served by the gateway on the swarm apex (services.hyperhive.swarm.domain) and readable only by operators.

Distinct from the per-hive dashboard, which lives on the hive domain and answers for one host. This one is the view across hives.

Enabling

services.hyperhive.swarm.ui.enable = true;   # defaults to swarm.controller.enable

Derived from the controller rather than from enableRequiredServices: the UI is a view onto the controller's state and reaches it over that daemon's socket, so the host that runs the controller is the host that can serve the UI. A hive that merely uses a swarm has nothing to serve.

swarm.ui.domain defaults to the swarm apex and can be pinned, the same way swarm.forge.domain and swarm.matrix.gatewayHost can.

The apex must differ from services.hyperhive.domain. The gateway's default server already answers for the hive domain, and two vhosts claiming one server_name do not error — nginx picks one — so this is an assertion rather than a runtime surprise.

🔑 You must be in the operators group

This is the step that separates "protected" from "locked out". The vhost's auth_request asks authelia "is there a session"; the rule that makes it mean "is this an operator" is an access_control entry requiring group:operators. An account without that group authenticates fine and still gets bounced.

swarmctl user add <you> --group operators

An account created before this existed has no groups. Re-add it with the flag — swarmctl treats an existing entry as the canonical store, so the group is what changes.

Why a group and not a list of usernames: agents are getting authelia accounts of their own (matrix SSO), and authenticated would then include every agent in the hive. The group is the only thing standing between "an operator's page" and "anyone with a session".

What it costs to be reachable

The apex is published to the hive's resolver like every other swarm service, so agent containers can resolve it. That is deliberate and it is not a hole: reachability is not the access control here. An agent that resolves the name and connects still has no operator session, and the subrequest denies it.

Four wiring sites

Adding a swarm service name means touching all four. Missing one ships as a different flavour of "works from the host, broken from a container":

site file
vhost nix/host-modules/hive-gateway/vhosts.nix
certificate name nix/host-modules/swarm.nix (serviceDomains)
DNS record nix/host-modules/hive-gateway/dnsmasq.nix
local-dev hosts nix/host-modules/hive-gateway/default.nix

⚠️ The certificate one is the least obvious and the most visible when missed. serviceDomains is both the services sub-CA's nameConstraints set and the leaf's SAN list, and the apex is a sibling of forge.<swarm> / chat.<swarm> / auth.<swarm>, not a parent — no CA in the hierarchy issues for it implicitly. Left out, the vhost falls back to the hive leaf and the swarm's front page opens with a name mismatch.

Cross-references

  • sso.md — the authelia instance itself, and the user store.
  • ../gateway.md — the full vhost map and TLS modes.