serve matrix discovery at the swarm apex, keep the pinned hive case
This commit is contained in:
parent
c9649b258f
commit
2e7d49bb88
10 changed files with 187 additions and 83 deletions
|
|
@ -1,16 +1,17 @@
|
|||
# Glue: serve the swarm homeserver's discovery on the hive domain's vhost
|
||||
# wherever both run.
|
||||
# Glue: matrix's links on the hive domain's vhost.
|
||||
#
|
||||
# ONE PAIRING PER FILE — matrix → hive domain vhost, and nothing else.
|
||||
# Deleting this leaves federation and clients with no `.well-known/matrix/*`
|
||||
# answer at the server name, and the legacy `<hive>/matrix/*` links 404.
|
||||
#
|
||||
# The locations sit on the hive domain because the matrix spec reads
|
||||
# delegation off the *server name*: it is the hive answering "where is my
|
||||
# homeserver", not the homeserver answering for itself (./hive-matrix.nix's
|
||||
# vhost on `gatewayHost` carries the rest).
|
||||
# Two pieces, each under its own condition:
|
||||
# - `.well-known/matrix/{client,server}` is served here only when the hive
|
||||
# domain IS the homeserver's server name (a homeserver that pinned
|
||||
# `swarm.matrix.serverName` to it): the spec reads delegation off the
|
||||
# *server name*. The host need not run the homeserver, since the JSON is
|
||||
# built from `swarm.matrix.gatewayHost` alone. For the default server name
|
||||
# (the swarm domain) the swarm UI's apex vhost answers (./swarm-ui.nix).
|
||||
# - `<hive>/matrix/*` redirects to the homeserver where the homeserver runs.
|
||||
#
|
||||
# ⚠️ The condition repeats the one ./hive-c0re/vhosts.nix declares the hive
|
||||
# ⚠️ Both conditions repeat the one ./hive-c0re/vhosts.nix declares the hive
|
||||
# domain vhost under. With it looser, this file alone would declare that
|
||||
# vhost, with discovery and no `/` redirect.
|
||||
{
|
||||
|
|
@ -24,53 +25,58 @@ let
|
|||
matrixCfg = hyperhiveCfg.swarm.matrix;
|
||||
|
||||
homeserverUrl = "https://${matrixCfg.gatewayHost}";
|
||||
|
||||
onHiveVhost =
|
||||
matrixCfg.gatewayHost != null
|
||||
&& hyperhiveCfg.deploy.hive-controller.enable
|
||||
&& gatewayCfg.enable
|
||||
&& hyperhiveCfg.swarm.dashboardDomain != null;
|
||||
|
||||
# Same default as `effectiveServerName` in ./hive-matrix.nix.
|
||||
serverName =
|
||||
if matrixCfg.serverName != null then matrixCfg.serverName else hyperhiveCfg.swarm.domain;
|
||||
in
|
||||
{
|
||||
config =
|
||||
lib.mkIf
|
||||
(
|
||||
hyperhiveCfg.deploy.matrix.enable
|
||||
&& matrixCfg.gatewayHost != null
|
||||
&& hyperhiveCfg.deploy.hive-controller.enable
|
||||
&& gatewayCfg.enable
|
||||
&& hyperhiveCfg.swarm.dashboardDomain != null
|
||||
)
|
||||
{
|
||||
services.hyperhive.gateway.vhosts.${hyperhiveCfg.domain}.locations = {
|
||||
# `<hive>/matrix/*` → 301 → `gatewayHost`'s vhost/$1 (`chat.<swarm-domain>`
|
||||
# by default; legacy deep-link shim for the fluffychat sub-domain).
|
||||
# See `docs/networking/gateway.md`.
|
||||
"/matrix/" = {
|
||||
extraConfig = ''
|
||||
rewrite ^/matrix/(.*)$ ${homeserverUrl}/$1 permanent;
|
||||
'';
|
||||
};
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf (onHiveVhost && hyperhiveCfg.deploy.matrix.enable) {
|
||||
# `<hive>/matrix/*` → 301 → `gatewayHost`'s vhost/$1 (`chat.<swarm-domain>`
|
||||
# by default; legacy deep-link shim for the fluffychat sub-domain).
|
||||
# See `docs/networking/gateway.md`.
|
||||
services.hyperhive.gateway.vhosts.${hyperhiveCfg.domain}.locations."/matrix/" = {
|
||||
extraConfig = ''
|
||||
rewrite ^/matrix/(.*)$ ${homeserverUrl}/$1 permanent;
|
||||
'';
|
||||
};
|
||||
})
|
||||
|
||||
# `.well-known/matrix/{client,server}` discovery JSON, pointing
|
||||
# clients and peers at `gatewayHost`: the homeserver has no other
|
||||
# address. CORS `*` per matrix spec. See `docs/networking/gateway.md`.
|
||||
"= /.well-known/matrix/client" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
${gatewayCfg.lib.securityHeaders}
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{"m.homeserver":{"base_url":"${homeserverUrl}"}}';
|
||||
'';
|
||||
};
|
||||
# `m.server` is NOT a URL: per the matrix server-server spec
|
||||
# (Resolving Server Names) a delegated host with NO port resolves
|
||||
# to the federation default 8448 (after the SRV check) — the
|
||||
# https-implies-443 rule does NOT apply here. So the port must be
|
||||
# explicit even when it's the HTTPS default, unlike the client
|
||||
# base_url above. Without it, peers federate to <gatewayHost>:8448
|
||||
# (closed) while the endpoint actually lives on the gateway's 443
|
||||
# vhost. See docs/networking/gateway.md discovery flow.
|
||||
"= /.well-known/matrix/server" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
return 200 '{"m.server":"${matrixCfg.gatewayHost}:443"}';
|
||||
'';
|
||||
};
|
||||
(lib.mkIf (onHiveVhost && hyperhiveCfg.domain == serverName) {
|
||||
services.hyperhive.gateway.vhosts.${hyperhiveCfg.domain}.locations = {
|
||||
# `.well-known/matrix/{client,server}` discovery JSON, pointing
|
||||
# clients and peers at `gatewayHost`: the homeserver has no other
|
||||
# address. CORS `*` per matrix spec. See `docs/networking/gateway.md`.
|
||||
"= /.well-known/matrix/client" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
${gatewayCfg.lib.securityHeaders}
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{"m.homeserver":{"base_url":"${homeserverUrl}"}}';
|
||||
'';
|
||||
};
|
||||
# `m.server` is NOT a URL: per the matrix server-server spec
|
||||
# (Resolving Server Names) a delegated host with NO port resolves
|
||||
# to the federation default 8448 (after the SRV check) — the
|
||||
# https-implies-443 rule does NOT apply here. So the port must be
|
||||
# explicit even when it's the HTTPS default, unlike the client
|
||||
# base_url above. Without it, peers federate to <gatewayHost>:8448
|
||||
# (closed) while the endpoint actually lives on the gateway's 443
|
||||
# vhost. See docs/networking/gateway.md discovery flow.
|
||||
"= /.well-known/matrix/server" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
return 200 '{"m.server":"${matrixCfg.gatewayHost}:443"}';
|
||||
'';
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ in
|
|||
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
|
||||
the controller's host 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.
|
||||
`chat.example.org` for a bespoke hostname).
|
||||
|
|
|
|||
|
|
@ -454,11 +454,10 @@ in
|
|||
# longest-prefix rule puts `/_matrix/`
|
||||
# ahead of `/` with no ordering needed.
|
||||
#
|
||||
# ⚠️ The `.well-known/matrix/*` delegation is deliberately NOT here.
|
||||
# It stays on the hive's own vhost because the spec requires it to
|
||||
# be served at the *server name*, which is the hive domain — it is
|
||||
# the hive answering "where is my homeserver", not the homeserver
|
||||
# answering for itself.
|
||||
# ⚠️ The `.well-known/matrix/*` delegation is deliberately NOT here:
|
||||
# the spec requires it at the *server name*. It is served by the swarm
|
||||
# apex (./swarm-ui.nix) for the default server name, or by the hive
|
||||
# domain's vhost (./glue-matrix-hive-discovery.nix) for a pinned one.
|
||||
services.hyperhive.gateway.vhosts = lib.optionalAttrs (cfg.gatewayHost != null) {
|
||||
"${cfg.gatewayHost}" = {
|
||||
locations = {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,16 @@ let
|
|||
# rather than a coercion error from here — same idiom as
|
||||
# `swarm-otel-service.nix`'s `domainBase`.
|
||||
apex = if swarmCfg.domain == null then "swarm.invalid" else swarmCfg.domain;
|
||||
|
||||
# Matrix discovery is answered at the server name, so the apex serves it when
|
||||
# that is the swarm domain (the default). A homeserver pinned to a hive
|
||||
# domain is answered by that hive's vhost (./glue-matrix-hive-discovery.nix).
|
||||
# Built from `gatewayHost` alone, so it does not matter which host runs the
|
||||
# homeserver. The URLs carry no port: `gateway.httpsPort` only sets what the
|
||||
# gateway listens on.
|
||||
matrixCfg = swarmCfg.matrix;
|
||||
serverName = if matrixCfg.serverName != null then matrixCfg.serverName else apex;
|
||||
servesMatrixDiscovery = matrixCfg.gatewayHost != null && serverName == apex;
|
||||
in
|
||||
{
|
||||
# No `enable` of its own: the UI is on wherever
|
||||
|
|
@ -196,6 +206,25 @@ in
|
|||
extraConfig = swarmAuthRequest;
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs servesMatrixDiscovery {
|
||||
# Same JSON, headers and `:443` as the hive-domain copy in
|
||||
# ./glue-matrix-hive-discovery.nix (see there for why `m.server` names
|
||||
# the port). No `auth_request`: peers and clients fetch these unauthenticated.
|
||||
"= /.well-known/matrix/client" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
${gatewayCfg.lib.securityHeaders}
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '{"m.homeserver":{"base_url":"https://${matrixCfg.gatewayHost}"}}';
|
||||
'';
|
||||
};
|
||||
"= /.well-known/matrix/server" = {
|
||||
extraConfig = ''
|
||||
default_type application/json;
|
||||
return 200 '{"m.server":"${matrixCfg.gatewayHost}:443"}';
|
||||
'';
|
||||
};
|
||||
}
|
||||
// {
|
||||
# swarm-controller's whole HTTP surface, including the live
|
||||
# `/api/openapi.json` spec — proxied untouched (no URI segment
|
||||
|
|
|
|||
Loading…
Reference in a new issue