feat(matrix-synapse): Gateway-API as an alternative to the Ingress
Group 3 of the #114 sweep. TWO HTTPRoutes - and the shape is not the one the issue described. #114 says this chart renders its Ingresses in a LOOP OVER SEVERAL APPS. It does not; that is freesailarr. It renders ONE Ingress object with TWO HOST rules: the homeserver on ingress.domain at "/", and the delegation nginx on matrix.delegation.serverUrl at "/.well-known/matrix". An HTTPRoute's spec.hostnames applies to the WHOLE object, so two hostnames that want different paths and different backends have to be two objects. That is the only faithful translation, not a stylistic choice. httpRoute.delegation.hostnames deliberately does NOT fall back to httpRoute.hostnames. The server name is what REMOTE homeservers resolve and is a different thing from the homeserver's own hostname; the migration order - homeserver host first, server name last - depends on telling them apart, and a chart-global hostname list covering both would erase the distinction. httpRoute.delegation.parentRefs falls back to httpRoute.parentRefs, which matters because the server name is usually an apex domain behind a different Gateway. ONE THING THIS MODE IMPROVES, and it is the awkward part of Matrix delegation. Under ingress-nginx two Ingress objects cannot both claim one hostname - the admission webhook rejects the second - which is why the delegation rule has to live inside this chart's single Ingress object even though the apex domain usually belongs to a website. HTTPRoutes attached to the same listener for the same hostname are merged by the implementation, longest match winning, so the /.well-known/matrix route can sit beside whatever owns that apex. WHAT THIS MODE DROPS, MEASURED ON THE LIVE OBJECT ON 2026-10-12 - and ONE OF THE TWO IS NOT WHAT IT LOOKS LIKE. The live Ingress carried, all of it operator-supplied through ingress.annotations (this chart sets none of it): nginx.ingress.kubernetes.io/proxy-body-size: 50m nginx.org/client-max-body-size: 50m nginx.ingress.kubernetes.io/configuration-snippet: | more_set_headers "X-Forwarded-For $remote_addr"; more_set_headers "X-Forwarded-Proto $scheme"; more_set_headers "Host $host:$server_port"; 1. THE BODY SIZE IS THE REAL LOSS. Synapse's media repository takes uploads; its own ceiling is max_upload_size in homeserver.yaml, which this chart cannot see because the whole config arrives from 1Password. The effective limit is the smaller of the two, and in this mode the proxy half becomes the GATEWAY'S default - neither number anyone can point at is necessarily the one that decides. No counterpart in the Gateway API, so per decision 2 of #114 it is documented, not rebuilt. nginx.org/client-max-body-size is the same limit spelled for NGINX Inc's controller, a hedge across both implementations, and it goes for the same reason. (#114's own measured table did not list matrix-synapse under proxy-body-size at all; the live object has it.) 2. THE SNIPPET IS NOT LOAD-BEARING, which took checking rather than assuming. It looks like what Synapse's x_forwarded setting depends on - client IP for rate limiting, and federation. It is not: more_set_headers is the headers-more module's OUTPUT-header directive ("Replaces (if any) or adds (if not any) the specified output headers"), the request-side directive being more_set_input_headers. So those three headers are added to the RESPONSE TO THE CLIENT; Synapse never sees them, and what it reads with x_forwarded: true is the REQUEST's X-Forwarded-For, which ingress-nginx supplies itself. The Gateway API's ResponseHeaderModifier could not rebuild it anyway (it knows no nginx variables), and should not: NOTES.txt says in as many words not to re-create it and not to read its absence as the cause of a rate-limiting or federation problem. Stated as what it is - a reading of the directive's documented semantics. Nothing here observed a Synapse instance with and without the snippet. NOTES.txt now asks $published (ingress.enabled OR httpRoute.enabled) wherever it used to ask ingress.enabled - the server-name/serverUrl mismatch warning, the "clients work fine" aside and the scaled-to-zero paragraph were all really asking whether anything publishes the release. Minor: additive, defaults unchanged. Empty helm template diff against origin/main with ci/matrix-synapse/test-values.yaml. Part of #114
This commit is contained in:
1 parent
9625d8b182
commit
e54cfe5fdd
6 files changed
+569
-17
No files matched your search
@@ -155,10 +155,133 @@ ingress:
|
||||
# read by the delegation nginx, which serves it in the /.well-known/matrix/*
|
||||
# endpoints, so it stays required whenever matrix.delegation.enabled is true.
|
||||
# Only clusterIssuer becomes unnecessary.
|
||||
#
|
||||
# MUTUALLY EXCLUSIVE WITH httpRoute.enabled - the render aborts when both are
|
||||
# true, and the message names both value paths.
|
||||
enabled: true
|
||||
domain: null
|
||||
clusterIssuer: null
|
||||
className: nginx
|
||||
# Extra annotations for the Ingress; merged with the cert-manager
|
||||
# cluster-issuer annotation the chart always sets.
|
||||
#
|
||||
# INERT IN GATEWAY MODE - the Gateway API has no annotation channel for
|
||||
# controller behaviour. For THIS chart that is not a formality: read the
|
||||
# httpRoute block below for what this installation actually has in here and
|
||||
# which half of it matters.
|
||||
annotations: {}
|
||||
|
||||
# THE GATEWAY-API ALTERNATIVE TO THE INGRESS (Gitea #114).
|
||||
#
|
||||
# Mutually exclusive with ingress.enabled - the render aborts when both are
|
||||
# true. The chart renders ONLY HTTPRoutes with parentRefs: no Gateway, no
|
||||
# class, no Certificate, and no implementation-specific policy object. Class
|
||||
# and certificate sit on the Gateway and its listeners and belong to the
|
||||
# platform (cluster-config), which is what keeps the Gateway implementation
|
||||
# replaceable without touching this chart again.
|
||||
#
|
||||
# TWO ROUTES, not one. The Ingress is a single object with two HOST rules - the
|
||||
# homeserver on ingress.domain at "/", and the delegation nginx on
|
||||
# matrix.delegation.serverUrl at "/.well-known/matrix". An HTTPRoute's
|
||||
# hostnames apply to the whole object, so two hostnames wanting different paths
|
||||
# and different backends must be two objects. (#114 describes this chart as
|
||||
# rendering its Ingresses in a loop over several apps; it does not - that is
|
||||
# freesailarr.)
|
||||
#
|
||||
# ONE THING THIS MODE MAKES EASIER, and it is the awkward part of Matrix
|
||||
# delegation: the server name is usually an apex domain that already serves a
|
||||
# website. Under ingress-nginx two Ingress objects cannot both claim one
|
||||
# hostname - the admission webhook rejects the second - which is why the
|
||||
# delegation rule has to live inside this chart's single Ingress object.
|
||||
# HTTPRoutes attached to the same listener for the same hostname are MERGED by
|
||||
# the implementation, longest match winning, so here the /.well-known/matrix
|
||||
# route can sit beside whatever owns that apex without either side knowing.
|
||||
#
|
||||
# WHAT THIS MODE COSTS, MEASURED ON THE LIVE OBJECT ON 2026-10-12, where the
|
||||
# Ingress carried - all of it OPERATOR-supplied through ingress.annotations,
|
||||
# since this chart sets none of it:
|
||||
#
|
||||
# nginx.ingress.kubernetes.io/proxy-body-size: 50m
|
||||
# nginx.org/client-max-body-size: 50m
|
||||
# nginx.ingress.kubernetes.io/configuration-snippet: |
|
||||
# more_set_headers "X-Forwarded-For $remote_addr";
|
||||
# more_set_headers "X-Forwarded-Proto $scheme";
|
||||
# more_set_headers "Host $host:$server_port";
|
||||
#
|
||||
# 1. THE BODY SIZE IS THE REAL LOSS. Synapse's media repository takes uploads
|
||||
# and its own ceiling is max_upload_size in homeserver.yaml - which this
|
||||
# chart cannot see, because the whole config comes from 1Password through
|
||||
# secrets.configSecretRef. The effective limit is the smaller of the two,
|
||||
# and in this mode the proxy half becomes THE GATEWAY'S default: neither
|
||||
# number anyone can point at is necessarily the one that decides. The
|
||||
# Gateway API has no body-size field, so per decision 2 of #114 this is
|
||||
# documented rather than rebuilt. Set it next to the Gateway, in that
|
||||
# implementation's own object, and set it to match max_upload_size.
|
||||
# (nginx.org/client-max-body-size is the same limit spelled for NGINX Inc's
|
||||
# ingress controller rather than ingress-nginx - a hedge across both - and
|
||||
# it goes for the same reason.)
|
||||
#
|
||||
# 2. THE SNIPPET IS NOT LOAD-BEARING, WHICH TOOK CHECKING. It looks like what
|
||||
# Synapse's x_forwarded setting depends on - client IP for rate limiting,
|
||||
# and federation. It is not: more_set_headers is the OUTPUT-header directive
|
||||
# of headers-more-nginx-module ("Replaces (if any) or adds (if not any) the
|
||||
# specified output headers"), while the request-side directive is
|
||||
# more_set_input_headers. These three headers are therefore added to the
|
||||
# RESPONSE TO THE CLIENT; Synapse never sees them, and what it reads with
|
||||
# x_forwarded: true is the REQUEST's X-Forwarded-For, which ingress-nginx
|
||||
# sets itself.
|
||||
#
|
||||
# So for the migration: not translatable, and not needed. The Gateway API's
|
||||
# ResponseHeaderModifier can set static response headers but knows no nginx
|
||||
# variables ($remote_addr, $scheme, $host), so rebuilding it is impossible
|
||||
# anyway - and pointless. Do NOT re-create it at the Gateway in the belief
|
||||
# that Synapse needs it.
|
||||
#
|
||||
# Stated as what it is: a reading of the directive's documented semantics.
|
||||
# Nothing here observed a Synapse instance with and without the snippet.
|
||||
#
|
||||
# THE GATEWAY-API CRDs MUST BE PRESENT. The chart cannot detect them
|
||||
# (.Capabilities.APIVersions is unreliable at template time) and an HTTPRoute
|
||||
# without them fails at install, so this is a value and not a guess.
|
||||
httpRoute:
|
||||
enabled: false
|
||||
|
||||
# The Gateway(s) the HOMESERVER route attaches to - a platform object,
|
||||
# usually in another namespace, whose listener must allow this namespace in
|
||||
# allowedRoutes. Entries are the Gateway API's ParentReference (name, and
|
||||
# optionally namespace, sectionName, port, group, kind), passed through
|
||||
# unchanged:
|
||||
#
|
||||
# parentRefs:
|
||||
# - name: public
|
||||
# namespace: gateway
|
||||
# sectionName: https
|
||||
#
|
||||
# REQUIRED while httpRoute.enabled is true - the render aborts on an empty
|
||||
# list, because a route without a parent is created, is valid and routes
|
||||
# nothing, with no event to say so.
|
||||
parentRefs: []
|
||||
|
||||
# Empty means [ingress.domain], so the homeserver hostname has one source of
|
||||
# truth. Set explicitly only to publish under a different or an additional
|
||||
# name - which is how a migration from the Ingress runs: the HTTPRoute takes
|
||||
# a second hostname while the Ingress keeps ingress.domain.
|
||||
#
|
||||
# THE DELEGATION HOST IS NOT COVERED BY THIS LIST, deliberately - see below.
|
||||
hostnames: []
|
||||
|
||||
delegation:
|
||||
# The delegation route's own parent. Empty falls back to
|
||||
# httpRoute.parentRefs. Worth setting when the SERVER NAME is published by
|
||||
# a different Gateway than the homeserver host, which is the normal case:
|
||||
# the server name is an apex domain somebody else's website usually owns.
|
||||
parentRefs: []
|
||||
|
||||
# Empty means [matrix.delegation.serverUrl], and it deliberately does NOT
|
||||
# fall back to httpRoute.hostnames. The server name is a different thing
|
||||
# from the homeserver's hostname - it is what REMOTE homeservers resolve -
|
||||
# and the migration order depends on telling them apart: move the
|
||||
# homeserver host first, confirm it answers, move the server name last.
|
||||
# A chart-global hostname list covering both would erase that distinction.
|
||||
# Set this only when the server name itself has to move.
|
||||
hostnames: []
|
||||
Reference in new issue
Block a user