feat(nix): the matrix server_name follows the swarm domain too

A swarm runs one homeserver, so its identity belongs to the swarm and
not to whichever hive happens to host it -- otherwise relocating the
container between hives reads as a different homeserver rather than a
move. `gatewayHost` moved for that reason a commit ago; `serverName`
was left behind, which made the identity hive-shaped and the routing
swarm-shaped.

⚠️ This is the one value on the page that a rebuild cannot undo.
`gatewayHost` is a routing detail clients rediscover through
`.well-known`; `server_name` is embedded in every user and room id, so
adopting a new one strands the existing accounts and rooms rather than
renaming them -- their ids still name a homeserver that stops
answering. Moving the DEFAULT is safe; moving a RUNNING deployment is
not, and existing hives must pin the value they already minted ids
under before rebuilding.

The fallback stays total on a null swarm domain for the same reason as
its neighbours: the required-domain assertion in hive-network.nix is
what should fire, not a coercion error from an unrelated option
interpolating null.

The legacy-pin eval probe now covers `serverName` as well. It existed
to answer "what do I set so old deployments don't change", and was
proving that only for the two values that are cheap to change -- the
irreversible one was the one it did not assert.
This commit is contained in:
atlas 2026-08-09 17:09:54 +02:00 committed by mara
commit a5210311bf
2 changed files with 81 additions and 44 deletions

View file

@ -7,14 +7,29 @@
let
cfg = config.services.hyperhive.swarm.matrix;
networkCfg = config.services.hyperhive.network;
hyperhiveDomain = config.services.hyperhive.domain;
swarmDomain = config.services.hyperhive.swarm.domain;
# ⚠️ Falls back to the HIVE domain, and must keep doing so even though
# `gatewayHost` moved to the swarm's: `serverName` is the matrix
# identifier baked into every user and room id, so changing it is a
# different homeserver rather than a rename. The two are independent on
# purpose — see the `gatewayHost` description below.
effectiveServerName = if cfg.serverName != null then cfg.serverName else hyperhiveDomain;
# Falls back to the SWARM domain: a swarm runs one homeserver, so its
# identifier belongs to the swarm rather than to whichever hive happens
# to host it — otherwise moving the container between hives would look
# like a different homeserver.
#
# ⚠️ Changing this default is a BREAKING change in a way that moving
# `gatewayHost` was not: `serverName` is baked irrevocably into every
# user and room id, so a deployment that rebuilds onto a new one is a
# *different homeserver*, not a renamed one. Existing hives pin the old
# value explicitly (see the option's description); the default is what
# a fresh swarm gets.
#
# Total on a null swarm domain, deliberately: the required-domain
# assertion in hive-network.nix is what should fire, not a coercion
# error from an unrelated option interpolating null.
effectiveServerName =
if cfg.serverName != null then
cfg.serverName
else if swarmDomain != null then
swarmDomain
else
"invalid";
# fluffychat-web build fixes: nixpkgs's `flutter341.buildFlutterApplication`
# skips the dart web-worker compile + the emscripten native_imaging
@ -137,21 +152,32 @@ in
Matrix `server_name` the host part of every user ID
(`@argus:<server_name>`) and room ID minted on this
homeserver. CRITICAL: must be stable from day one because
it's embedded irrevocably in the identifiers. Defaults to
`services.hyperhive.domain` (the bare hive domain). Combined
with the `.well-known/matrix/{client,server}` routes the
hive-gateway serves at that domain, clients auto-discover the
it's embedded irrevocably in the identifiers.
Defaults to `services.hyperhive.swarm.domain` (the bare swarm
domain), because **a swarm runs one homeserver** tying its
identity to a single hive's domain would make relocating the
container between hives look like a different homeserver.
Combined with the `.well-known/matrix/{client,server}` routes
the gateway serves at that domain, clients auto-discover the
actual matrix endpoint without needing a subdomain. Override
here only if you need a different server_name shape (e.g.
`matrix.<domain>` if you want the subdomain split, or
`chat.example.org` for a bespoke hostname).
**Breaking change**: this used to default to
`matrix.''${services.hyperhive.domain}`. matrix IDs embed
the server_name irrevocably, so existing homeservers must
set `services.hyperhive.swarm.matrix.serverName = "matrix.''${services.hyperhive.domain}";`
explicitly to preserve their existing user / room IDs
before rebuilding.
**Breaking change, and the one on this page that cannot be
undone by rebuilding.** This default has now moved twice from
`matrix.''${services.hyperhive.domain}`, then to the bare hive
domain, and now to the swarm domain. Every existing homeserver
must pin whichever value it already minted ids under, e.g.
```nix
services.hyperhive.swarm.matrix.serverName =
config.services.hyperhive.domain; # or "matrix.''${…domain}"
```
before rebuilding. Adopting a new `server_name` does not rename
the old users and rooms it strands them, because their ids
still name a homeserver that no longer answers.
'';
};
@ -219,13 +245,14 @@ in
bottom of that doc.
**`gatewayHost` and `serverName` are different things, and
only this one moved.** `gatewayHost` is the API listener
hostname (where nginx proxies `/_matrix/*`) and is free to
change: it is a routing detail clients rediscover through
`.well-known`. `serverName` is the matrix-identifier domain
embedded **irrevocably** in every user and room id changing
that is a different homeserver, not a rename, so it still
defaults to the bare hive domain and is untouched here.
they carry very different costs.** `gatewayHost` is the API
listener hostname (where nginx proxies `/_matrix/*`) and is
free to change: it is a routing detail clients rediscover
through `.well-known`. `serverName` is the matrix-identifier
domain embedded **irrevocably** in every user and room id
adopting a new one is a different homeserver, not a rename.
Both defaults now sit under the swarm domain, but only this
one is safe to move on a running deployment.
A deployment that was running before this moved keeps its
current name by pinning