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:

  1. Install Syncthing on the remote device
  2. Get its device ID: syncthing device-id --home=<home-dir>
  3. Add the device ID to the server's config.xml (both in the <device> section and in the <folder> section)
  4. Add the server's device ID to the remote device's configuration
  5. 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.