Setting Up Syncthing for File Synchronization
August 7, 2026
Syncthing is a peer-to-peer file synchronization tool that replaces proprietary services like Dropbox. Files sync directly between your devices with no central server — the data never passes through a third party. On a server, Syncthing acts as an always-on sync peer that keeps a canonical copy of your shared folders. This post covers installing Syncthing on Gentoo, generating keys and device IDs, writing the configuration, creating an OpenRC service, and optionally proxying the web UI through Apache.
Installing Syncthing
On Gentoo
emerge -av net-p2p/syncthing dev-python/bcrypt
The bcrypt package is needed for hashing the web UI password. Syncthing's GUI stores passwords as bcrypt hashes in its configuration file.
On Debian
apt install -y syncthing
On Alpine
apk add syncthing
Creating the Service User and Directories
Syncthing should run as a dedicated user rather than root. For servers where Syncthing shares data with a web application (e.g., Nextcloud), running as the web server user avoids permission issues:
mkdir -p /var/lib/syncthing
chown apache:apache /var/lib/syncthing
chmod 750 /var/lib/syncthing
If you prefer a dedicated user:
useradd -r -d /var/lib/syncthing -s /sbin/nologin syncthing
mkdir -p /var/lib/syncthing
chown syncthing:syncthing /var/lib/syncthing
chmod 750 /var/lib/syncthing
Create the shared folder base directory:
mkdir -p /var/syncthing/shared
chown apache:apache /var/syncthing/shared
chmod 755 /var/syncthing/shared
Generating Keys and Device ID
Syncthing identifies each device by a unique ID derived from its TLS certificate. Generate the keys and get the device ID:
syncthing generate --home=/var/lib/syncthing
Run this as the Syncthing user:
su -s /bin/sh -c 'syncthing generate --home=/var/lib/syncthing' apache
Retrieve the device ID:
su -s /bin/sh -c 'syncthing device-id --home=/var/lib/syncthing' apache
This outputs a string like:
AAAAAAA-BBBBBBB-CCCCCCC-DDDDDDD-EEEEEEE-FFFFFFF-GGGGGGG-HHHHHHH
Save this ID — you'll need it when configuring other devices to connect to this one.
Generating the GUI Password Hash
Syncthing stores the web UI password as a bcrypt hash. Generate one:
python3 -c "import bcrypt; print(bcrypt.hashpw(b'your-gui-password', bcrypt.gensalt()).decode())"
This outputs a hash like:
$2b$12$LJ3m4ys3yz5K8v9ZrT5lLuWVx2QYb5aO4TIJK3mB6N9HstWfEn0Ea
Save this hash for the configuration file.
Writing the Configuration
Syncthing's configuration lives in config.xml inside its home directory. Write /var/lib/syncthing/config.xml:
<configuration version="37">
<folder id="default" label="Shared" path="/var/syncthing/shared"
type="sendreceive" rescanIntervalS="3600"
fsWatcherEnabled="true" fsWatcherDelayS="10"
ignorePerms="false" autoNormalize="true">
<filesystemType>basic</filesystemType>
<device id="YOUR-SERVER-DEVICE-ID" introducedBy="">
<encryptionPassword></encryptionPassword>
</device>
<device id="YOUR-OTHER-DEVICE-ID" introducedBy="">
<encryptionPassword></encryptionPassword>
</device>
<minDiskFree unit="%">1</minDiskFree>
<versioning>
<type>simple</type>
<params>
<keep>5</keep>
</params>
<cleanupIntervalS>3600</cleanupIntervalS>
</versioning>
</folder>
<device id="YOUR-SERVER-DEVICE-ID" name="myserver"
compression="metadata" introducer="false">
<address>dynamic</address>
<paused>false</paused>
</device>
<device id="YOUR-OTHER-DEVICE-ID" name="workstation"
compression="metadata" introducer="false">
<address>dynamic</address>
<paused>false</paused>
</device>
<gui enabled="true" tls="false" debugging="false">
<address>127.0.0.1:8384</address>
<user>admin</user>
<password>YOUR-BCRYPT-HASH-HERE</password>
<insecureSkipHostcheck>true</insecureSkipHostcheck>
</gui>
<options>
<listenAddress>tcp://:22000</listenAddress>
<listenAddress>quic://:22000</listenAddress>
<globalAnnounceEnabled>false</globalAnnounceEnabled>
<localAnnounceEnabled>false</localAnnounceEnabled>
<relaysEnabled>false</relaysEnabled>
<natEnabled>false</natEnabled>
<startBrowser>false</startBrowser>
<urAccepted>-1</urAccepted>
<autoUpgradeIntervalH>0</autoUpgradeIntervalH>
<crashReportingEnabled>false</crashReportingEnabled>
</options>
</configuration>
Set ownership and permissions:
chown apache:apache /var/lib/syncthing/config.xml
chmod 600 /var/lib/syncthing/config.xml
Configuration Decisions
globalAnnounceEnabled: false — disables the global discovery server. On a public-facing server with a known IP, you don't need discovery — devices connect directly. This reduces external dependencies and prevents your device ID from being published to Syncthing's discovery infrastructure.
localAnnounceEnabled: false — disables LAN discovery broadcasts. Not useful on a server.
relaysEnabled: false — disables relay connections. Relays route traffic through third-party servers when direct connections fail. On a server with open ports, relays are unnecessary and add latency.
natEnabled: false — disables NAT traversal. A server typically has a public IP or a port forwarded through the firewall. NAT traversal is for devices behind consumer routers.
autoUpgradeIntervalH: 0 — disables automatic upgrades. On a server, packages should be updated through the package manager, not by the application itself.
Simple versioning with keep: 5 — Syncthing keeps the 5 most recent versions of each file in a .stversions directory. This provides a safety net against accidental deletions or overwrites without consuming excessive disk space.
Listen addresses: TCP and QUIC on port 22000 — Syncthing supports both TCP and QUIC protocols. QUIC can be faster on high-latency connections. Both listen on the standard Syncthing port.
GUI bound to 127.0.0.1:8384 — the web interface only listens on localhost. Access it through an SSH tunnel or a reverse proxy (covered below).
Creating the OpenRC Service
Create the init script at /etc/init.d/syncthing:
#!/sbin/openrc-run
name="Syncthing"
description="Syncthing file synchronization"
command="/usr/bin/syncthing"
command_args="serve --no-browser --home=/var/lib/syncthing"
command_user="apache:apache"
command_background="yes"
pidfile="/run/${RC_SVCNAME}.pid"
output_log="/var/log/syncthing.log"
error_log="/var/log/syncthing.log"
depend() {
need net
after firewall
}
start_pre() {
checkpath --directory --owner apache:apache --mode 0750 "/var/lib/syncthing"
checkpath --file --owner apache:apache --mode 0644 /var/log/syncthing.log
}
Set permissions and enable:
chmod 755 /etc/init.d/syncthing
rc-update add syncthing default
rc-service syncthing start
On Debian (systemd)
Debian's Syncthing package includes a systemd user service. To run it as a system service:
systemctl enable syncthing@syncthing
systemctl start syncthing@syncthing
Replace syncthing with the username you want to run Syncthing as.
Firewall Configuration
Syncthing needs port 22000 open for device-to-device connections:
# iptables
iptables -A INPUT -p tcp --dport 22000 -j ACCEPT
iptables -A INPUT -p udp --dport 22000 -j ACCEPT
If you're using QUIC, the UDP rule is required. If you only use TCP, you can skip the UDP rule.
Proxying the Web UI Through Apache
To access Syncthing's web UI through a domain name with TLS, configure Apache as a reverse proxy. First, ensure the proxy module is enabled.
On Gentoo, add the PROXY flag to /etc/conf.d/apache2:
APACHE2_OPTS="... -D PROXY"
You may need to rebuild Apache with proxy support:
cat > /etc/portage/package.use/apache-syncthing << 'EOF'
www-servers/apache proxy proxy_http
EOF
emerge -uN www-servers/apache
Create the virtual host at /etc/apache2/vhosts.d/syncthing.example.com.conf:
<VirtualHost *:443>
ServerName syncthing.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8384/
ProxyPassReverse / http://127.0.0.1:8384/
<Location />
Require ip 192.168.1.0/24
</Location>
</VirtualHost>
The Require ip directive restricts access to your local network. Adjust the IP range to match your admin network. You can also use Syncthing's built-in authentication instead of IP restrictions.
Restart Apache:
rc-service apache2 restart
Adding Remote Devices
To sync with another device:
- Install Syncthing on the remote device
- Get its device ID:
syncthing device-id --home=<home-dir> - Add the device ID to the server's
config.xml(both in the<device>section and in the<folder>section) - Add the server's device ID to the remote device's configuration
- Restart Syncthing on both sides
Both devices must list each other in their configurations and share at least one folder for synchronization to begin.
Verifying the Installation
Check that Syncthing is running:
rc-status | grep syncthing
Check that the sync protocol is listening:
ss -lnt sport = :22000
Check the web UI is accessible via localhost:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8384/
This should return 200 (or 401 if authentication is enabled).
Check the log for errors:
tail -20 /var/log/syncthing.log
Summary
After completing these steps:
- Syncthing runs as a system service under a dedicated user
- Files sync directly between devices with no cloud intermediary
- Global discovery, relays, and NAT traversal are disabled for a server environment
- The web UI is accessible through an Apache reverse proxy with IP restrictions
- Simple versioning keeps 5 copies of changed files as a safety net
- The sync protocol listens on both TCP and QUIC for compatibility
Syncthing pairs well with Nextcloud — you can sync the Nextcloud data directory between servers for redundancy, or use Syncthing for files that don't need a web interface.