Skip to main content

Relay Servers and NAT Traversal

Most devices live behind NAT routers that block incoming connections. Syncthing solves this with two mechanisms: NAT traversal (hole-punching via QUIC/UTP) and relay servers as a fallback.

Learning Focus

Understand the performance cost of relay connections and know when to configure a direct port forward instead to keep sync fast.

Tool Snapshot
Connection TypeSpeedLatencyPrivacyWhen Used
Direct TCP (port 22000)FastestLowestP2P encryptedBoth peers publicly reachable
QUIC NAT traversalFastLowP2P encryptedBoth peers behind NAT, traversal succeeds
Relay (relays.syncthing.net)SlowestHighestEncrypted, relay sees metadataAll direct attempts fail

Connection Negotiation Flow

flowchart TD
A[Device A wants to sync with Device B] --> B[Try direct TCP on port 22000]
B --> C{Success?}
C -- Yes --> G[Direct P2P sync — fastest]
C -- No --> D[Try QUIC NAT hole-punch]
D --> E{Success?}
E -- Yes --> G
E -- No --> F[Fall back to Relay server]
F --> H[Relay-mediated sync — slowest but works]

You can see the active connection type in the GUI under each device's status: Direct, Relayed, or Disconnected.

Checking Connection Type from Logs

check-connection-type.sh
# Watch connection events
journalctl --user -u syncthing -f | grep -E "Connected|relay|direct"

# Example output:
# INFO: Connected to K3X2R... at tcp://203.0.113.45:22000 (direct)
# INFO: Connected to K3X2R... at relay://relay.example.com:22067 (relayed)

Enabling/Disabling Relays

Relays are enabled by default. On a VPS with a public IP, disable relays and use a direct port forward instead:

config.xml — disable relays
<options>
<relaysEnabled>false</relaysEnabled>
</options>

To keep relays but prefer direct connections:

<options>
<relaysEnabled>true</relaysEnabled>
<!-- Relay connection rate limit — prevents relay abuse -->
<relayReconnectIntervalM>10</relayReconnectIntervalM>
</options>

Running a Self-Hosted Relay

For organizations behind strict firewalls or wanting full control:

deploy-relay-server.sh
# Install strelaysrv
go install github.com/syncthing/syncthing/cmd/strelaysrv@latest

# Run relay on port 22067 (data) and 22070 (status)
strelaysrv -listen ":22067" -status-srv ":22070"

# Get the relay URI (needed for clients)
# Output: relay://YOUR.SERVER.IP:22067/?id=DEVICE_ID&pingInterval=60s&networkTimeout=2m0s

In each client's config.xml:

config.xml — use custom relay
<options>
<relayServer>relay://YOUR.SERVER.IP:22067/?id=DEVICE_ID</relayServer>
</options>
note

Self-hosted relays require TCP ports 22067 and 22070 open in your firewall. The public Syncthing relay pool at relays.syncthing.net is used by default and is rate-limited per device for fairness.

NAT Traversal with a VPS Port Forward

The cleanest approach for a server with a public IP: open port 22000 and let Syncthing establish direct connections without relays.

open-sync-port.sh
# UFW
sudo ufw allow 22000/tcp
sudo ufw allow 22000/udp # for QUIC
sudo ufw reload

# iptables
sudo iptables -A INPUT -p tcp --dport 22000 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 22000 -j ACCEPT

Verify Syncthing is listening:

ss -tlnp | grep 22000
ss -ulnp | grep 22000

Troubleshooting Matrix

SymptomCauseFix
Always "Relayed" even with public VPSPort 22000 not openufw allow 22000/tcp udp
Relay connection very slowLarge file sets through community relaysHost your own relay or use direct connection
"No relay found" errorAll relays unreachableCheck DNS and HTTPS to relays.syncthing.net
QUIC not workingUDP 22000 blockedAllow UDP 22000 in firewall

What's Next