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:

  1. Server discovery. Remote servers must know which hostname and port your server listens on. This is resolved via either a .well-known file or DNS SRV records.
  2. TLS certificate. The connection must present a valid TLS certificate for your server name.
  3. 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:

FieldExpectedProblem If Not
ConnectionReports.*.ResulttrueFirewall or proxy issue
DNSResult.SRVRecords or WellKnownResultValid entriesDiscovery configuration wrong
Version.nameSynapseServer not responding correctly
ValidCertificatestrueTLS 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-known instead of SRV records. .well-known is simpler, more debuggable, and the recommended approach. SRV records are a fallback.

Comments