Matrix Synapse: Federation Not Working — Fix
The Problem
Your Matrix Synapse homeserver runs fine locally — users can log in, create rooms, and send messages — but federation with other servers fails. You can’t join rooms on other homeservers, remote users can’t find your server, or messages from federated rooms don’t arrive.
Common error messages in Synapse logs:
ERROR - Failed to send request to remote server: ConnectionRefused
WARNING - Received 401 response from remote server
ERROR - Could not resolve server name for federation
INFO - No .well-known found for matrix.example.com
The Matrix Federation Tester at https://federationtester.matrix.org reports failures like CanReachViaHTTPS: false, DNSCheck: false, or WellKnownResult: failure.
The Cause
Federation requires remote Matrix servers to reach your server over HTTPS. Three things must work correctly:
- Server discovery. Remote servers must know which hostname and port your server listens on. This is resolved via either a
.well-knownfile or DNS SRV records. - TLS certificate. The connection must present a valid TLS certificate for your server name.
- Network connectivity. Port 8448 (default federation port) or your custom port must be reachable from the public internet.
Most federation failures come from incorrect .well-known configuration, reverse proxy misconfiguration, or firewall rules blocking port 8448.
The Fix
Method 1: Configure .well-known (Most Common Fix)
If your Matrix server name (server_name in homeserver.yaml) is example.com but Synapse actually runs on matrix.example.com, you need .well-known delegation.
Serve this JSON file at https://example.com/.well-known/matrix/server:
{
"m.server": "matrix.example.com:443"
}
And this at https://example.com/.well-known/matrix/client:
{
"m.homeserver": {
"base_url": "https://matrix.example.com"
}
}
Using Nginx:
# On the example.com web server (not the Matrix server)
location /.well-known/matrix/server {
return 200 '{"m.server": "matrix.example.com:443"}';
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
}
location /.well-known/matrix/client {
return 200 '{"m.homeserver": {"base_url": "https://matrix.example.com"}}';
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
}
Using Caddy:
example.com {
handle /.well-known/matrix/server {
header Content-Type application/json
header Access-Control-Allow-Origin *
respond `{"m.server": "matrix.example.com:443"}`
}
handle /.well-known/matrix/client {
header Content-Type application/json
header Access-Control-Allow-Origin *
respond `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
}
}
Test the .well-known response:
curl -s https://example.com/.well-known/matrix/server | python3 -m json.tool
Method 2: Fix Reverse Proxy Headers
If Synapse is behind Nginx, Traefik, or Caddy, the reverse proxy must pass correct headers. Missing or wrong headers cause federation requests to be rejected.
Nginx configuration for Synapse:
server {
listen 443 ssl http2;
server_name matrix.example.com;
# SSL certificate configuration here
location /_matrix {
proxy_pass http://localhost:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
client_max_body_size 50M;
}
location /_synapse {
proxy_pass http://localhost:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
}
}
Critical: In homeserver.yaml, add your reverse proxy’s IP to the trusted proxy list:
# homeserver.yaml
listeners:
- port: 8008
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
The x_forwarded: true setting tells Synapse to trust the X-Forwarded-For header from your proxy. Without this, Synapse may reject federation requests because it sees the proxy’s IP instead of the remote server’s IP.
Traefik users: If using Traefik with Docker networking, ensure Synapse’s port is exposed in the Docker Compose file (not just via Traefik labels). Traefik’s default network routing can interfere with federation IP verification.
Method 3: Open Federation Port
By default, Matrix federation uses port 8448. If your firewall blocks this port, remote servers can’t reach you.
# Check if port 8448 is reachable
nc -zv your-server-ip 8448
# Open port on UFW
sudo ufw allow 8448/tcp
# Open port on iptables
sudo iptables -A INPUT -p tcp --dport 8448 -j ACCEPT
Alternative: Use port 443 for federation. If you can’t open port 8448 (some hosting providers block non-standard ports), route federation through port 443 using .well-known delegation (Method 1). Set "m.server": "matrix.example.com:443" and ensure your reverse proxy forwards both client and federation traffic.
Method 4: Fix DNS Records
Verify your DNS records are correct:
# Check A record for your Matrix server
dig +short matrix.example.com A
# Check for SRV record (optional, .well-known is preferred)
dig +short _matrix-fed._tcp.example.com SRV
If using .well-known delegation (recommended over SRV), you don’t need a SRV record. The A record for matrix.example.com must point to your server’s public IP.
Method 5: Verify with the Federation Tester
After making changes, test with the official tester:
curl -s "https://federationtester.matrix.org/api/report?server_name=example.com" | python3 -m json.tool
Or visit https://federationtester.matrix.org/#example.com in a browser.
Key fields to check:
| Field | Expected | Problem If Not |
|---|---|---|
ConnectionReports.*.Result | true | Firewall or proxy issue |
DNSResult.SRVRecords or WellKnownResult | Valid entries | Discovery configuration wrong |
Version.name | Synapse | Server not responding correctly |
ValidCertificates | true | TLS certificate issue |
Prevention
- Test federation immediately after initial setup — don’t wait until a user reports it.
- Monitor the federation tester periodically. DNS changes, certificate renewals, or reverse proxy updates can break federation silently.
- Pin your reverse proxy configuration. Document the exact Nginx/Traefik/Caddy config that works. Federation is sensitive to header changes.
- Use
.well-knowninstead of SRV records..well-knownis simpler, more debuggable, and the recommended approach. SRV records are a fallback.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments