diff --git a/nix/modules/hive-gateway.nix b/nix/modules/hive-gateway.nix index b838cbc1..7ce91da8 100644 --- a/nix/modules/hive-gateway.nix +++ b/nix/modules/hive-gateway.nix @@ -641,6 +641,72 @@ in }; }; }; + + # `_` (default) server location groups, lifted out of the inline + # `//`-chain so the two matrix groups (each with its own `let`) + # read on their own. Composed into the `_` vhost's `locations` + # below alongside the still-inline agent/dashboard/auth groups. + + # `/matrix/*` → 301 → `matrix./$1` (legacy deep-link + # shim during the fluffychat sub-domain move). See `docs/gateway.md`. + matrixRedirectLocations = + lib.optionalAttrs (matrixCfg.enable && matrixCfg.gui.enable && matrixCfg.gatewayHost != null) + ( + let + target = "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}"; + in + { + "/matrix/" = { + extraConfig = '' + rewrite ^/matrix/(.*)$ ${target}/$1 permanent; + ''; + }; + } + ); + + # `.well-known/matrix/{client,server}` discovery JSON. Points + # clients at `matrixCfg.gatewayHost` when set; falls back to direct + # `:`. CORS `*` per matrix spec. The `m.server` + # port-8448 carve-out is documented inline. See `docs/gateway.md`. + wellKnownLocations = lib.optionalAttrs (matrixCfg.enable && hyperhiveDomain != null) ( + let + clientBaseUrl = + if matrixCfg.gatewayHost != null then + "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}" + else + "${publicScheme}://${hyperhiveDomain}:${toString matrixCfg.httpPort}"; + # `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; `publicPortSuffix` + # (which drops :443) is right for the client base_url above but + # wrong for federation delegation. Without this, peers federate to + # :8448 (closed) while the endpoint actually lives on + # the gateway's 443 vhost. See docs/gateway.md discovery flow. + serverHostPort = + if matrixCfg.gatewayHost != null then + "${matrixCfg.gatewayHost}:${toString publicPort}" + else + "${hyperhiveDomain}:${toString matrixCfg.httpPort}"; + in + { + "= /.well-known/matrix/client" = { + extraConfig = '' + default_type application/json; + ${securityHeaders} + add_header Access-Control-Allow-Origin *; + return 200 '{"m.homeserver":{"base_url":"${clientBaseUrl}"}}'; + ''; + }; + "= /.well-known/matrix/server" = { + extraConfig = '' + default_type application/json; + return 200 '{"m.server":"${serverHostPort}"}'; + ''; + }; + } + ); in { system.stateVersion = "26.05"; @@ -762,72 +828,8 @@ in "_" = vhostTls // { listen = vhostListen; locations = - # `/matrix/*` → 301 → `matrix./$1` - # (fluffychat moved to sub-domain root; this - # keeps bookmarks + deep-links working during the - # transition). See `docs/gateway.md` for the vhost - # map. - lib.optionalAttrs (matrixCfg.enable && matrixCfg.gui.enable && matrixCfg.gatewayHost != null) ( - let - target = "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}"; - in - { - "/matrix/" = { - extraConfig = '' - rewrite ^/matrix/(.*)$ ${target}/$1 permanent; - ''; - }; - } - ) - // - # `.well-known/matrix/{client,server}` discovery JSON. - # Points clients at `matrixCfg.gatewayHost` (sub-domain - # vhost) when set; falls back to direct `:` - # when no gateway target. CORS `*` per matrix spec. - # See `docs/gateway.md` "Discovery flow" for the full - # client-bootstrap sequence. - lib.optionalAttrs (matrixCfg.enable && hyperhiveDomain != null) ( - let - clientBaseUrl = - if matrixCfg.gatewayHost != null then - "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}" - else - "${publicScheme}://${hyperhiveDomain}:${toString matrixCfg.httpPort}"; - # `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; `publicPortSuffix` (which drops - # :443) is right for the client base_url above but - # wrong for federation delegation. Without this, - # peers federate to :8448 (closed) while - # the endpoint actually lives on the gateway's 443 - # vhost. See docs/gateway.md discovery flow. - serverHostPort = - if matrixCfg.gatewayHost != null then - "${matrixCfg.gatewayHost}:${toString publicPort}" - else - "${hyperhiveDomain}:${toString matrixCfg.httpPort}"; - in - { - "= /.well-known/matrix/client" = { - extraConfig = '' - default_type application/json; - ${securityHeaders} - add_header Access-Control-Allow-Origin *; - return 200 '{"m.homeserver":{"base_url":"${clientBaseUrl}"}}'; - ''; - }; - "= /.well-known/matrix/server" = { - extraConfig = '' - default_type application/json; - return 200 '{"m.server":"${serverHostPort}"}'; - ''; - }; - } - ) + matrixRedirectLocations + // wellKnownLocations // # `/agent/` catch-all: hits when an operator # requests `/agent//...`. Without this the