This adds a new routing mechanism for sync workers that resolves access tokens
to usernames via Synapse's whoami endpoint, enabling true user-level sticky
routing regardless of which device or token is used.
Previously, sticky routing relied on parsing the username from native Synapse
tokens (`syt_<base64 username>_...`), which only works with native Synapse auth
and provides device-level stickiness at best. This new approach works with any
auth system (native Synapse, MAS, etc.) because Synapse handles token validation
internally.
Implementation uses nginx's auth_request module with an njs script because:
- The whoami lookup requires an async HTTP subrequest (ngx.fetch)
- js_set handlers must return synchronously and don't support async operations
- auth_request allows the async lookup to complete, then captures the result
via response headers into nginx variables
The njs script:
- Extracts access tokens from Authorization header or query parameter
- Calls Synapse's whoami endpoint to resolve token -> username
- Caches results in a shared memory zone to minimize latency
- Returns the username via a `X-User-Identifier` header
The username is then used by nginx's upstream hash directive for consistent
worker selection. This leverages nginx's built-in health checking and failover.
On ansible-core 2.19.0, invoking macro like this (which only outputted
something in its `if` block, not in `else`), resulted in a macro
outputting `None`.
One way to work around it is to add an explicit `else` block which also
outputs something.
A better way to work around it is to only invoke the macro if it
has something to output.
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/4458
Since nginx 1.27.3, we can make use of the `resolve` parameter for an `upstream`'s `server`,
to allow DNS resolution to happen continuously at runtime, not just once during startup.
Previously, this was not possible to do in an `upstream` block without
an nginx-plus subscription. Outside of an `upstream` block, we've used
and still use `set $backend ..` workarounds to get DNS resolution at
runtime, but now we can do it in `upstream` as well.
Until now, most sections were specifying their own values for these.
For `client_max_body_size`, a value of 25MB was hardcoded in most places.
This was generally OK, but..
Some sections (those generated by the `render_locations_to_upstream` macro), were not specifying these options
and were ending up with a default value for configuration options for `client_max_body_size` (likely 1MB), etc.
From now on:
- we use individual variables for defining these for the Client-Server
and Federation API and apply these once at the `server` level
- we keep auto-determining the `client_max_body_size` for the
Client-Server API based on `matrix_synapse_max_upload_size_mb`
- we keep auto-calculating the `client_max_body_size` for the Federation
API based on the one for the Client API, but now also add a "minimum"
value (`matrix_synapse_reverse_proxy_companion_federation_api_client_max_body_size_mb_minimum: 100`)
to ensure we don't go too low
Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/4100
gzipping certain responses is known to cause problems with QR code logins.
Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/3749
Gzipping at the synapse-reverse-proxy-companion level and not at the
level of the outer-most reverse-proxy (Traefik) also sounds non-ideal.
This change only affects setups powered by Synapse workers.
Non-worker setups (and setups powered by other homeservers) were not
having their requests go through synapse-reverse-proxy-companion anyway,
so this change does not affect them.
Future patches may enable response compression support at the Traefik level for
all setups.