Fri 2020-09-25 16:37
I'm going to throw this up here because I've not found it documented elsewhere and it took me a bit to figure out.
Let's say you want to setup a file synchronization connection between two remote hosts that don't share connectivity (e.g., WAN, VPN, etc.). You might rightly suggest Syncthing as a solution. Install Syncthing on each host and configure the hosts to share one or more sync'd folders. Great, but what if both hosts are behind a NAT firewall and neither of these hosts have open ports exposed to the public Internet?
No problem. Syncthing normally solves this limitation by using relay hosts, of which there is a public pool run by the Syncthing project and other volunteers. Two Syncthing clients that need to share files but cannot directly connect to one another discover a mutually accessible relay server and use that host to connect. The relay servers themselves do not keep a copy of any sync'd files. They don't even have the ability to read the files being synchronized between clients. Instead, they only register clients and forward Syncthing traffic between them, allowing hosts to sync files without direct connectivity.
Okay, simple enough. However, let's add a wrinkle to this problem and suppose that you don't want the synchronized files to traverse any third-party servers. Perhaps you want to control all servers in the file sync path, or provide dedicated resources to ensure that your relayed files don't have to compete with other files being relayed. Or maybe security is a concern. True, Syncthing traffic is encrypted end-to-end... but still. Maybe it's just paranoia or maybe it's due to regulatory compliance and security audits, but you don't want the synchronized files to pass through unknown systems. Further, you might not even want the Syncthing clients to use the Syncthing global discovery servers and share metadata publicly.
The somewhat documented solution for that requirement is to run your own private instance of the Syncthing Relay Server on a trusted public-facing host to which both syncing hosts have access.
Installing and configuring the Syncthing Relay Server itself is not that difficult. If you're running a major Linux distro there's probably a package for it in your repos (for fellow openSUSE users it's the
syncthing-relaysrv package.) To run a private instance that does not join the Syncthing relay pool, start the service with the following option flags:
/usr/bin/strelaysrv -pools="" -status-srv=""
The first time Syncthing Relay Server is run it will generate its crypto keys and Syncthing device ID. Thereafter, each time the service is run it will report it's own relay URI, which will be in the form
relay://ip_address:port/?id=syncthing_id. As instructed in the Syncthing documentation, you can configure the Syncthing client to use the relay by going to Actions / Settings / Connections and editing the Sync Protocol Listen Addresses field. Remove
default and add the normal listening ports and the relay URI provided by the relay host. For a relay at 22.214.171.124 on port 23456, the field might look like:
tcp://:22000, quic://:22000, relay://126.96.36.199:23456/?id=EAD3F29EDC...
Turn off Enable NAT traversal, Global Discovery, and Local Discovery. Make sure Enable Relaying is turned on.
If you restart Syncthing on the client hosts and check the client logs, you should see a secure connection established to the relay. If you look at the IP connections on the relay using
ss you should see connections from both clients.
Now here's the (afaik) undocumented part: how in the name of Odin's right buttcheek do you get the two clients to find each other through the relay? This is not immediately obvious, and much searching and parsing docs revealed no answers on the matter. It turns out it is relatively simple.
First, you will need the Syncthing device ID of each host (Actions / Show ID). Copy those down and share the partner ID with each client in the connection (the IDs are public keys, and are not secret info).
Next, on each client create a remote device for the opposite host (via + Add Remote Device). On the General tab, enter the Device ID and Device Name as normal.
Up to this point, things are pretty typical for making a connection to a Syncthing peer. But one more step is required to allow the hosts to discover each other and connect via the relay.
On the Advanced tab of the remote device configuration page, edit the Addresses field. Remove
dynamic and replace it with the relay URI (e.g.
relay://188.8.131.52:23456/?id=EAD3F29EDC...). Click Save.
Once that has been done on both sides (a Syncthing restart may be required), the two hosts should now discover each other through the relay to which they are both registered and folders can now be shared and sync'd. So simple, but definitely not self-evident.
Anyway, I hope the above info spares someone else a couple hours of their life mucking around with Syncthing trying to figure this out.