Add documentation for matrix federation + traefik labels for federation via port 8448 on matrix-federation entrypoint #62
@ -23,9 +23,15 @@ SECRET_REGISTRATION_VERSION=v1
|
||||
|
||||
#DISABLE_FEDERATION=1
|
||||
|
||||
# SERVE_SERVER_WELLKNOWN only works if SERVER_NAME and DOMAIN are the same
|
||||
|
3wordchant marked this conversation as resolved
Outdated
|
||||
# if they are different, then a different federation method is needed (like compose.wellknown.yml)
|
||||
# Set "true" to enable federation endpoint on $DOMAIN/.well-known/matrix/server
|
||||
SERVE_SERVER_WELLKNOWN=false
|
||||
|
||||
# Serve /.well-known/matrix/{server,client} on SERVER_NAME via Traefik.
|
||||
# Can be used when SERVER_NAME != DOMAIN and SERVER_NAME is served by Traefik.
|
||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.wellknown.yml"
|
||||
|
||||
ALLOW_PUBLIC_ROOMS_FEDERATION=false
|
||||
|
||||
## Registration
|
||||
|
||||
93
README.md
93
README.md
@ -39,11 +39,100 @@
|
||||
|
||||
### Enabling federation
|
||||
|
||||
See [`#27`](https://git.coopcloud.tech/coop-cloud/matrix-synapse/pulls/27) for more. Depending on your setup, using `SERVE_SERVER_WELLKNOWN=true` might work to start federating. Make sure you don't leave `DISABLE_FEDERATION=1` set!
|
||||
Federation is on by default (`DISABLE_FEDERATION=0`). Remote homeservers need a way to discover the host:port that serves your `SERVER_NAME`.
|
||||
There are three supported approaches. At least one needs to be working for federation to work (and matrix will fallback between them).
|
||||
|
||||
#### Option 1: built-in well-known (`SERVER_NAME` = `DOMAIN`)
|
||||
|
||||
Set `SERVE_SERVER_WELLKNOWN=true` and leave `SERVER_NAME` unset (defaults to `DOMAIN`). The recipe's nginx serves `/.well-known/matrix/server` and `/.well-known/matrix/client` on `DOMAIN`.
|
||||
|
||||
Suitable when users are e.g. `@alice:matrix.example.com`.
|
||||
|
||||
#### Option 2: external well-known on `SERVER_NAME`
|
||||
|
||||
|
3wordchant marked this conversation as resolved
3wordchant
commented
Maybe "and when the apex domain is served by the same machine than Synapse is running on"? Maybe "and when the apex domain is served by the same machine than Synapse is running on"?
notplants
commented
hmm I also think your phrase seems easier to understand, and i'm not 100% sure but I think maybe technically this stuff could apply even when SERVER_NAME is not apex domain ... but surely the most common situation where SERVER_NAME does not equal DOMAIN is when SERVER_NAME is apex and DOMAIN (of synapse) is a subdomain hmm I also think your phrase seems easier to understand, and i'm not 100% sure but I think maybe technically this stuff could apply even when SERVER_NAME is not apex domain ...
like could have SERVER_NAME = matrix.mydomain.tld
DOMAIN = synapse.mydomain.tld
but surely the most common situation where SERVER_NAME does not equal DOMAIN is when SERVER_NAME is apex and DOMAIN (of synapse) is a subdomain
notplants
commented
ah I am reading what you wrote differently now. an additional AND clause. I will add this ah I am reading what you wrote differently now. an additional AND clause. I will add this
```
Use when you want users to be e.g. `@alice:example.com` while Synapse runs at `matrix.example.com` and SERVER_NAME is served by the same machine that Synapse is running on.
```
|
||||
Use when you want users to be e.g. `@alice:example.com` while Synapse runs at `matrix.example.com` (and SERVER_NAME is served by the same machine that Synapse is running on). Set:
|
||||
|
||||
```
|
||||
SERVER_NAME=example.com
|
||||
DOMAIN=matrix.example.com
|
||||
SERVE_SERVER_WELLKNOWN=false
|
||||
```
|
||||
|
||||
The two paths that must be served on `SERVER_NAME` are:
|
||||
|
||||
- `https://example.com/.well-known/matrix/server` → `{"m.server": "matrix.example.com:443"}`
|
||||
- `https://example.com/.well-known/matrix/client` → `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
|
||||
|
||||
**Recommended — let this recipe serve them via Traefik** by enabling `compose.wellknown.yml`:
|
||||
|
||||
```
|
||||
COMPOSE_FILE="$COMPOSE_FILE:compose.wellknown.yml"
|
||||
```
|
||||
|
||||
This publishes a Traefik router `Host(${SERVER_NAME}) && PathPrefix(/.well-known/matrix)`
|
||||
pointing at the matrix nginx, which already serves both files. The path-scoped, high-priority
|
||||
rule coexists with any apex website that also serves `Host(${SERVER_NAME})` — that site keeps
|
||||
serving everything except `/.well-known/matrix`. `SERVER_NAME` must resolve to this Traefik so
|
||||
ACME can issue its certificate.
|
||||
|
||||
**Alternative** — serve the two files yourself from whatever already hosts `example.com`.
|
||||
|
||||
|
||||
#### Option 3: Traefik `matrix-federation` entrypoint (port 8448)
|
||||
|
||||
|
3wordchant marked this conversation as resolved
3wordchant
commented
Ditto, requires apex pointing to same server. Ditto, requires apex pointing to same server.
notplants
commented
ty, added ty, added
|
||||
Use when `SERVER_NAME` ≠ `DOMAIN` but you have no separate web service at `SERVER_NAME`. Remote homeservers fall back to `SERVER_NAME:8448` when there's no delegation (also requires SERVER_NAME pointing to same server that matrix is running on).
|
||||
|
||||
Requirements:
|
||||
|
||||
- [traefik](https://git.coopcloud.tech/coop-cloud/traefik) `>= 5.1.2+v3.6.15` with `MATRIX_FEDERATION_ENABLED=1` and `compose.matrix.yml` enabled.
|
||||
- `SERVER_NAME` set in your matrix-synapse env (used by the federation router's Host rule).
|
||||
|
||||
With these in place, the recipe publishes a Traefik router on `Host(${SERVER_NAME})` via the `matrix-federation` entrypoint, reusing the existing matrix nginx → synapse path.
|
||||
|
||||
|
||||
#### Option 4: DNS SRV records (usually not viable here)
|
||||
|
||||
For reasons explained below, I might be confused, but I think SRV records usually don't help with co-op cloud matrix deployments.
|
||||
|
||||
You should probably prefer Option 2 (well known), but the possibility of SRV is explained below:
|
||||
|
||||
Federation can also be delegated with a DNS `SRV` record on `SERVER_NAME` instead of well-known:
|
||||
|
||||
```
|
||||
_matrix-fed._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # modern
|
||||
_matrix._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # deprecated, for older peers
|
||||
```
|
||||
|
||||
The catch is TLS: on the SRV path a remote validates the certificate against **`SERVER_NAME`**, *not* the SRV target. This recipe's Traefik only issues a cert for **`DOMAIN`**, so:
|
||||
|
3wordchant marked this conversation as resolved
3wordchant
commented
Maybe worth moving this warning higher up in the section? Maybe worth moving this warning higher up in the section?
notplants
commented
ty, I moved this up ty, I moved this up
|
||||
|
||||
- **SRV → `DOMAIN`:443 fails** — the presented cert is for `DOMAIN`, but the peer requires one for `SERVER_NAME`.
|
||||
- **SRV → `SERVER_NAME`:443 collides** — Traefik routes TLS by SNI, and `Host(SERVER_NAME)` on `:443` is already owned by whatever apex site serves `SERVER_NAME`.
|
||||
- **SRV → `SERVER_NAME`:8448 works** — the Option 3 `matrix-federation` router holds a cert for `SERVER_NAME` — but that's just Option 3 made explicit (the `:8448` fallback already works with no SRV record).
|
||||
|
||||
|
||||
#### Verifying
|
||||
|
||||
The canonical test:
|
||||
|
||||
- https://federationtester.matrix.org/#YOUR_SERVER_NAME
|
||||
|
||||
Or check the underlying paths directly. They should all return JSON:
|
||||
|
||||
```bash
|
||||
# Options 1 & 2 — delegation
|
||||
curl https://SERVER_NAME/.well-known/matrix/server
|
||||
|
||||
# Option 3 — federation endpoint via 8448
|
||||
curl https://SERVER_NAME:8448/_matrix/key/v2/server
|
||||
|
||||
# Confirms Synapse itself is healthy (independent of the path remote servers use)
|
||||
curl https://DOMAIN/_matrix/key/v2/server
|
||||
```
|
||||
|
||||
### Getting client discovery on a custom domain
|
||||
|
||||
You'll need to deploy something like [this](https://git.autonomic.zone/ruangrupa/well-known-uris). This could be implemented in this recipe but we haven't merged it in yet. Change sets are welcome.
|
||||
Enable `compose.wellknown.yml` (see Option 2 above) — it serves `/.well-known/matrix/client`
|
||||
on `SERVER_NAME` too, so clients signing in as `@alice:example.com` auto-discover the homeserver.
|
||||
|
||||
## Bridges
|
||||
For all Bridges:
|
||||
|
||||
24
compose.wellknown.yml
Normal file
24
compose.wellknown.yml
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
version: "3.8"
|
||||
|
||||
# Serve /.well-known/matrix/{server,client} on SERVER_NAME via Traefik, routed to
|
||||
# the matrix nginx (`web`) — so server/client delegation works without hand-placing
|
||||
# files on whatever else hosts SERVER_NAME.
|
||||
#
|
||||
# Enable when SERVER_NAME != DOMAIN (users are @alice:example.com, Synapse runs at
|
||||
# matrix.example.com). The PathPrefix rule is more specific than a bare Host()
|
||||
# router, and the explicit high priority guarantees it wins over any apex website
|
||||
# that also serves Host(SERVER_NAME) — so the two coexist, the apex site keeps
|
||||
# serving everything except /.well-known/matrix.
|
||||
#
|
||||
# Requires SERVER_NAME to resolve to this Traefik so ACME can issue its cert.
|
||||
services:
|
||||
web:
|
||||
deploy:
|
||||
labels:
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.rule=Host(`${SERVER_NAME}`) && PathPrefix(`/.well-known/matrix`)"
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.tls=true"
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.service=${STACK_NAME}"
|
||||
- "traefik.http.routers.${STACK_NAME}-wellknown.priority=1000"
|
||||
@ -29,6 +29,11 @@ services:
|
||||
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)"
|
||||
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
|
||||
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}-federation.rule=Host(`${SERVER_NAME}`)"
|
||||
- "traefik.http.routers.${STACK_NAME}-federation.entrypoints=matrix-federation"
|
||||
- "traefik.http.routers.${STACK_NAME}-federation.tls=true"
|
||||
- "traefik.http.routers.${STACK_NAME}-federation.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||
- "traefik.http.routers.${STACK_NAME}-federation.service=${STACK_NAME}"
|
||||
healthcheck:
|
||||
test: curl -f http://${STACK_NAME}_app:8008/health || exit 1
|
||||
interval: 30s
|
||||
|
||||
Reference in New Issue
Block a user
Maybe worth mentioning in the
.envas well that only one method is necessary? It's in the README already though so 🤷agreed. added some comments to .env.sample in case the operator doesn't make it to the readme