Watch
0
0
Fork
You've already forked hyperhive
0

matrix: serve the web client unconditionally; link it from the swarm domain

Removes services.hyperhive.deploy.matrix.gui.enable and its
swarm.matrix.gui.enable alias; both are mkRemovedOptionModule stubs. A
host running the homeserver serves fluffychat at gatewayHost's vhost,
and the hive's /matrix/ redirect follows the same condition.

The swarm-controller builds the Matrix quick link from
swarm.matrix.gatewayHost, replacing hive-matrix.nix's per-host entry.
HIVE_MATRIX_PUBLIC_URL is set on every hive with a gatewayHost, so
`hivectl open matrix` resolves off the homeserver's host too.

Drops HIVE_MATRIX_GUI_ENABLED and the dashboard's matrix_gui_enabled
field; nothing in the frontend reads it.

Refs #4885
This commit is contained in:
atlas 2026-10-02 18:41:21 +02:00
commit f60f8af33b
10 changed files with 48 additions and 96 deletions

View file

@ -8,7 +8,7 @@ homeserver, on one host. Two namespaces configure it:
- `services.hyperhive.swarm.matrix.*` — what the homeserver **is**, as
every hive sees it: `serverName`, `gatewayHost`, ports, `allowEncryption`.
- `services.hyperhive.deploy.matrix.*` — what the host running it decides:
`enable`, `gui.enable`, `openFirewall`, `trustedServers`,
`enable`, `gui.package`, `openFirewall`, `trustedServers`,
`maxRequestSize`, `sso.clientSecretFile`.
Vhost routing lives in [`gateway.md`](../networking/gateway.md).

View file

@ -113,19 +113,19 @@ same whichever host runs each service:
| Grafana | `services.hyperhive.swarm.grafana.domain` |
| Metrics | `services.hyperhive.swarm.victoriametrics.domain` |
| Logs | `services.hyperhive.swarm.victorialogs.domain` |
| Matrix | `services.hyperhive.swarm.matrix.gatewayHost` |
`nix/host-modules/swarm-controller.nix` builds these entries. The
Matrix and Forge entries, and `swarm-ui.nix`'s entry for this UI's own API
docs, come from those services' own modules, and only when the controller's
host runs that service. An operator can add entries directly. An
empty list hides the button.
`nix/host-modules/swarm-controller.nix` builds these entries. The Forge
entry, and `swarm-ui.nix`'s entry for this UI's own API docs, come from
those services' own modules, and only when the controller's host runs that
service. An operator can add entries directly. An empty list hides the
button.
The **Matrix** entry opens the swarm's matrix web client (fluffychat,
`services.hyperhive.deploy.matrix.gui.package`) at the homeserver's
gateway host, `chat.<swarm domain>` by default. `hive-matrix.nix` adds it
only when `services.hyperhive.deploy.matrix.gui.enable` is on and the
homeserver has a gateway host, the same condition under which that vhost
serves the client at `/`.
gateway host, `chat.<swarm domain>` by default. The homeserver's host
always serves the client at `/` on that vhost, so the entry is present
whenever the swarm names a gateway host.
<details><summary>Adding a swarm service name: the two wiring sites</summary>

View file

@ -73,12 +73,6 @@ pub(super) struct StateSnapshot {
/// links each container's config + each approval's commit into the
/// forge's `agent-configs` repos.
forge_present: bool,
/// Whether `services.hyperhive.deploy.matrix.gui.enable` is on. Sourced
/// from the `HIVE_MATRIX_GUI_ENABLED` env var the c0re NixOS module
/// sets. The matrix client itself is served on the homeserver's
/// gateway vhost; the hive's `/matrix/` path redirects there
/// (`nix/host-modules/hive-gateway/vhosts.nix`).
matrix_gui_enabled: bool,
/// Whether `hive-gateway` is in front of this dashboard. Sourced
/// from the `HIVE_GATEWAY_ENABLED` env var, which the c0re NixOS
/// module now always sets (the gateway runs unconditionally
@ -313,17 +307,10 @@ pub(super) async fn api_state(
tombstones,
port_conflicts,
forge_present: crate::forge::is_present().await,
matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_ENABLED").is_some_and(|v| {
// Accept any truthy string ("1", "true", "yes") since the
// env var is set by NixOS module wiring with the literal
// "1"; defensive parse so manual overrides also work.
let s = v.to_string_lossy().to_ascii_lowercase();
matches!(s.as_str(), "1" | "true" | "yes")
}),
gateway_enabled: std::env::var_os("HIVE_GATEWAY_ENABLED").is_some_and(|v| {
// Same truthy-string parse as `matrix_gui_enabled`; the
// env var is set by the c0re NixOS module to the literal
// "1" — the gateway always runs alongside hyperhive.
// Accept any truthy string ("1", "true", "yes"): the c0re
// NixOS module sets the literal "1" (the gateway always runs
// alongside hyperhive), and manual overrides also parse.
let s = v.to_string_lossy().to_ascii_lowercase();
matches!(s.as_str(), "1" | "true" | "yes")
}),

View file

@ -30,7 +30,7 @@ pub(crate) async fn open_url(socket: &Path, target: OpenTarget) -> Result<()> {
),
OpenTarget::Matrix => (
urls.matrix,
"the matrix GUI URL needs `services.hyperhive.deploy.matrix.gui.enable = true`",
"the matrix GUI URL needs `services.hyperhive.swarm.matrix.gatewayHost` set",
),
};
let url = url.with_context(|| format!("no URL available for this surface — {hint}"))?;

View file

@ -277,10 +277,16 @@ in
The old token file at /var/lib/hyperhive/matrix-register-token is read by
nothing now and can be deleted. See docs/integrations/matrix.md.
'')
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "matrix" "gui" "enable" ]
[ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ]
)
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "gui" "enable" ] ''
The matrix web client has no on/off switch: every host that runs the
homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost,
and the swarm UI links to it. Remove this definition.
'')
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ] ''
The matrix web client has no on/off switch: every host that runs the
homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost,
and the swarm UI links to it. Remove this definition.
'')
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "swarm" "matrix" "sso" "clientSecretFile" ]
[ "services" "hyperhive" "deploy" "matrix" "sso" "clientSecretFile" ]

View file

@ -191,12 +191,6 @@ in
# one.
HIVE_MATRIX_API_URL = config.services.hyperhive.swarm.matrix.apiUrl;
}
// lib.optionalAttrs config.services.hyperhive.deploy.matrix.gui.enable {
# Surfaces as `matrix_gui_enabled` in the dashboard's `/api/state`.
# The matrix GUI is served entirely by the gateway nginx. Gateway
# routing detail: docs/networking/gateway.md::Vhost map.
HIVE_MATRIX_GUI_ENABLED = "1";
}
// {
# The gateway always runs, so the dashboard always builds
# same-origin `/agent/<name>/` links (never the direct
@ -216,17 +210,11 @@ in
# forge links rather than emitting one it can't justify.
HIVE_FORGE_PUBLIC_URL = config.services.hyperhive.swarm.forge.publicUrl;
}
//
lib.optionalAttrs
(
config.services.hyperhive.deploy.matrix.gui.enable
&& config.services.hyperhive.swarm.matrix.gatewayHost != null
)
{
// lib.optionalAttrs (config.services.hyperhive.swarm.matrix.gatewayHost != null) {
# Browser-facing matrix GUI (fluffychat) URL — the gateway
# vhost (`gatewayHost`, `chat.<swarm-domain>` by default). Surfaced via the daemon's `Urls`
# request for `hivectl open matrix`. Absent when the GUI is off
# or no gatewayHost is set (no browser-reachable matrix vhost).
# request for `hivectl open matrix`. Absent when no gatewayHost is
# set (no browser-reachable matrix vhost).
HIVE_MATRIX_PUBLIC_URL = "https://${config.services.hyperhive.swarm.matrix.gatewayHost}/";
}
// lib.optionalAttrs (config.services.hyperhive.swarm.snapshotStore.address != null) {

View file

@ -46,8 +46,7 @@ let
# by default; legacy deep-link shim during the fluffychat sub-domain move).
# See `docs/networking/gateway.md`.
matrixRedirectLocations =
lib.optionalAttrs
(matrixDeployCfg.enable && matrixDeployCfg.gui.enable && matrixCfg.gatewayHost != null)
lib.optionalAttrs (matrixDeployCfg.enable && matrixCfg.gatewayHost != null)
(
let
target = "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}";

View file

@ -537,22 +537,6 @@ in
'';
};
gui.enable = lib.mkOption {
type = lib.types.bool;
default = deployCfg.matrix.enable;
defaultText = lib.literalExpression "config.services.hyperhive.deploy.matrix.enable";
description = ''
Serve a matrix web client at `gatewayHost`'s vhost (`chat.<swarm-domain>`
by default) and add the swarm UI's **Matrix** quick link to it
(`services.hyperhive.swarm.controller.links`). Requires
`gatewayHost != null`; the gateway itself always runs. See
`docs/networking/gateway.md` for the discovery flow that lets clients
auto-find the sub-domain. The client build itself is
`deploy.matrix.gui.package` — which client, as opposed to whether
this host serves it.
'';
};
gui.package = lib.mkOption {
type = lib.types.package;
default = fluffychat-web-fixed;
@ -667,19 +651,6 @@ in
# through the hive's dnsmasq whether or not the gateway fronts it.
services.hyperhive.gateway.dns.enable = lib.mkDefault true;
# This swarm-ui quick-links entry. Gated on `gui.enable` too, not just
# `gatewayHost != null`: `/` on that vhost only serves fluffychat
# (below) when the GUI is on — otherwise the link would 404. See
# docs/swarm/ui.md::Quick links and
# `services.hyperhive.swarm.controller.links`'s description.
services.hyperhive.swarm.controller.links =
lib.optional (cfg.gatewayHost != null && deployCfg.matrix.gui.enable)
{
label = "Matrix";
icon = "💬";
url = "https://${cfg.gatewayHost}/";
};
# Accept-header SPA map, used only by the `/` location below (see
# docs/networking/gateway.md "SPA fallback"): text/html → index.html, else a
# sentinel so `try_files` falls through to 404. `appendHttpConfig`
@ -687,7 +658,7 @@ in
# contributes instead of replacing it.
#
# The dashboard needs no equivalent — it routes by path.
services.nginx.appendHttpConfig = lib.optionalString deployCfg.matrix.gui.enable ''
services.nginx.appendHttpConfig = ''
map $http_accept $matrix_spa_target {
default "/__matrix_spa_no_html_fallback";
"~*text/html" "/index.html";
@ -695,8 +666,8 @@ in
'';
# `server_name = gatewayHost`. `/_matrix/*` → tuwunel (CORS `*`, 50M
# body cap, 1h long-poll timeout). `/` serves fluffychat, or 404
# with the GUI off. nginx's longest-prefix rule puts `/_matrix/`
# body cap, 1h long-poll timeout). `/` serves fluffychat. nginx's
# longest-prefix rule puts `/_matrix/`
# ahead of `/` with no ordering needed.
#
# ⚠️ The `.well-known/matrix/*` delegation is deliberately NOT here.
@ -727,8 +698,6 @@ in
add_header Access-Control-Allow-Origin *;
'';
};
}
// lib.optionalAttrs deployCfg.matrix.gui.enable {
# fluffychat at sub-domain root, SPA-fallback via the
# Accept-header `$matrix_spa_target` map above.
"/" = {
@ -746,11 +715,6 @@ in
return 200 '{"defaultHomeserver":"${hyperhiveDomain}"}';
'';
};
}
// lib.optionalAttrs (!deployCfg.matrix.gui.enable) {
"/" = {
return = "404";
};
};
};
};

View file

@ -51,7 +51,14 @@ let
icon = "📜";
inherit (swarmCfg.victorialogs) domain;
}
];
]
# A null `gatewayHost` means no vhost fronts the homeserver, so there is
# no web client to link to.
++ lib.optional (swarmCfg.matrix.gatewayHost != null) {
label = "Matrix";
icon = "💬";
url = "https://${swarmCfg.matrix.gatewayHost}/";
};
# Where the secret store is, and whether this host holds the controller's
# own leaf for it. ⚠️ The controller's pair, NOT `deploy.bao.clientCertFile`
@ -451,8 +458,9 @@ in
or swarm-ui change.
The Authelia, Grafana, Metrics and Logs entries come from
`services.hyperhive.swarm.<service>.domain`, so they are present
whichever host runs each service. `hive-matrix.nix`,
`services.hyperhive.swarm.<service>.domain`, and the Matrix entry
from `services.hyperhive.swarm.matrix.gatewayHost` when it is set,
so they are present whichever host runs each service.
`hive-forge/default.nix` and `swarm-ui.nix` contribute their own
entries, and only where they are enabled on this host.

View file

@ -115,9 +115,9 @@ let
Grafana = s.grafana.domain;
Metrics = s.victoriametrics.domain;
Logs = s.victorialogs.domain;
Matrix = s.matrix.gatewayHost;
# forge: added once hive-forge/default.nix drops its per-host link
# matrix: added once its GUI gate is settled
# bao: added once its UI gate is settled
# bao: its web UI at `swarm.bao.ui.domain` has no link yet
};
swarmServiceLinksOf =
cfg: