Secure File Sync Between Linux Servers with Syncthing and WireGuard (Step-by-Step)

Why Syncthing + WireGuard is a smart choice

When you need reliable file synchronization between Linux servers, it’s tempting to reach for classic tools like rsync over SSH or an NFS share. Those options still work, but they can be painful when you have multiple sites, changing IP addresses, strict firewalls, or you want near real-time updates without a central storage server. A modern approach is to combine Syncthing (continuous, peer-to-peer file sync) with WireGuard (fast, secure VPN). You get encrypted transport, stable private IPs, and a sync tool that can handle intermittent connectivity gracefully.

This tutorial shows how to set up Syncthing to sync a directory between two Linux servers over a WireGuard tunnel. The result is a private “always-on” sync link that doesn’t require exposing Syncthing to the public internet.

What you’ll build

You will configure:

Server A: 10.10.10.1 (WireGuard interface: wg0)

Server B: 10.10.10.2 (WireGuard interface: wg0)

Syncthing will bind to the WireGuard interface so sync traffic stays inside the VPN. We’ll also harden firewall rules and enable Syncthing as a system service.

Prerequisites

Before you start, make sure both servers have sudo access and can reach each other on the internet (at least one side needs a reachable UDP port for WireGuard). You should also know which folder you want to sync, for example /srv/sync. This guide assumes Ubuntu/Debian-style commands; on RHEL/Fedora you can adapt package manager commands accordingly.

Step 1: Install WireGuard on both servers

On both servers, install WireGuard:

Debian/Ubuntu: sudo apt update && sudo apt install -y wireguard

Enable IP forwarding is not required for a simple point-to-point sync tunnel, but it doesn’t hurt to keep routing simple and only use the tunnel addresses for Syncthing.

Step 2: Create WireGuard keys

On each server, generate a keypair:

umask 077
wg genkey | tee ~/wg-private.key | wg pubkey > ~/wg-public.key

Copy each server’s wg-public.key to the other side. Keep private keys private.

Step 3: Configure the WireGuard tunnel

On Server A, create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.10.10.1/24
PrivateKey = SERVER_A_PRIVATE_KEY
ListenPort = 51820

[Peer]
PublicKey = SERVER_B_PUBLIC_KEY
AllowedIPs = 10.10.10.2/32
PersistentKeepalive = 25

On Server B, create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.10.10.2/24
PrivateKey = SERVER_B_PRIVATE_KEY

[Peer]
PublicKey = SERVER_A_PUBLIC_KEY
Endpoint = SERVER_A_PUBLIC_IP:51820
AllowedIPs = 10.10.10.1/32
PersistentKeepalive = 25

Start and enable the tunnel on both servers:

sudo systemctl enable --now wg-quick@wg0

Test connectivity:

ping -c 3 10.10.10.2 (from Server A)
ping -c 3 10.10.10.1 (from Server B)

Step 4: Install Syncthing on both servers

Install Syncthing from your distro repo or the official package source. On Debian/Ubuntu, the repo version may be older, but it still works. For a straightforward setup:

sudo apt update && sudo apt install -y syncthing

Step 5: Run Syncthing as a service (recommended)

Create a dedicated user (optional but clean) and run Syncthing under it. For a fast setup using your current user, enable the user service:

systemctl --user enable --now syncthing

If you prefer a system-wide service tied to a specific account:

sudo systemctl enable --now [email protected]

Step 6: Bind Syncthing to WireGuard only

To keep sync traffic inside the VPN, open Syncthing’s Web UI locally (or via SSH port forwarding) and adjust settings:

1) In Settings > Connections, set Listen Addresses to include the WireGuard IP, for example: tcp://10.10.10.1:22000 (Server A) and tcp://10.10.10.2:22000 (Server B).

2) Optionally disable global discovery and relays for a pure VPN setup: turn off Global Discovery and Enable Relaying. This reduces external dependencies and noise.

Step 7: Pair the devices and add a synced folder

In the Syncthing Web UI on Server A, click Add Remote Device, paste Server B’s Device ID, and save. Do the same in the other direction if it doesn’t auto-accept. Then add a folder such as /srv/sync on Server A and share it with Server B. On Server B, accept the share and choose the local path where files should land.

If you’re syncing application data, be mindful of file locks and databases. For PostgreSQL/MySQL, sync dumps or backups instead of live database files. For configs, scripts, and documents, Syncthing is a perfect fit.

Step 8: Firewall tips for a locked-down setup

At minimum, allow WireGuard UDP on the server that listens publicly (Server A in this example). With UFW:

sudo ufw allow 51820/udp

You do not need to expose Syncthing ports to the internet if it’s bound to the WireGuard IP. If you manage Syncthing’s UI remotely, use SSH port forwarding rather than opening the GUI port globally.

Troubleshooting checklist

No tunnel connection: verify public IP/port, confirm keys, and check sudo wg show for latest handshake times.

Devices don’t see each other: confirm Syncthing is listening on the WireGuard IP and that you used the correct Device IDs. Test with nc -vz 10.10.10.2 22000 across the tunnel.

Permissions problems: ensure the Syncthing service user can read/write the synced folder. Fix with ownership or ACLs.

Final notes

With Syncthing running over WireGuard, you get a clean and modern file sync stack: encrypted transport, stable addressing, and continuous synchronization without exposing extra services to the public internet. This approach scales nicely as you add more servers—just add peers to WireGuard and devices to Syncthing, then share the folders you need.

Comments