Syncthing is an open source, peer-to-peer file synchronization tool. Devices exchange data directly over TLS-encrypted connections, so no third-party cloud ever holds a copy of your files. In this tutorial you will install Syncthing on an Ubuntu 24.04 server, run it as a systemd service for a regular user, reach its web interface securely through an SSH tunnel, pair a second device, and share a folder with file versioning and ignore patterns.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with a non-root user that has sudo privileges. This guide uses your_user for that account.
  • A second device to sync with (a laptop or another server) with Syncthing installed. Desktop builds are available from the official Syncthing website.
  • UFW enabled on the server, or another firewall you can open ports on.

Syncthing uses these ports:

PortProtocolPurpose
22000TCP and UDPSync protocol (TCP and QUIC)
21027UDPLocal network discovery
8384TCPWeb GUI (keep it on localhost)

Step 1 - Adding the official Syncthing repository

Ubuntu's own syncthing package usually lags behind upstream. The Syncthing project runs an APT repository that always ships the current stable release, signed with its own key.

Install curl and create the keyring directory:

sudo apt update
sudo apt install -y curl
sudo install -m 0755 -d /etc/apt/keyrings

Download the release signing key:

sudo curl -fsSL -o /etc/apt/keyrings/syncthing-archive-keyring.gpg https://syncthing.net/release-key.gpg

Add the repository. The stable-v2 channel tracks the Syncthing 2.x series:

echo "deb [signed-by=/etc/apt/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable-v2" | sudo tee /etc/apt/sources.list.d/syncthing.list

Refresh the package index and confirm that the candidate version comes from apt.syncthing.net:

sudo apt update
apt policy syncthing
syncthing:
  Installed: (none)
  Candidate: 2.0.x
  Version table:
     2.0.x 500
        500 https://apt.syncthing.net syncthing/stable-v2 amd64 Packages

Step 2 - Installing Syncthing

Install the package:

sudo apt install -y syncthing

Check the installed version:

syncthing --version
syncthing v2.0.x "..." (go1.24.x linux-amd64) ...

The package also installs a systemd template unit, [email protected], which runs Syncthing as whichever user you pass after the @.

Step 3 - Running Syncthing as a systemd service

Run Syncthing under your regular user, not root. It will then own the files it syncs and can only touch what that user can access. Replace your_user with your username:

sudo systemctl enable --now syncthing@your_user.service

Check that the service is active:

systemctl status syncthing@your_user.service
● syncthing@your_user.service - Syncthing - Open Source Continuous File Synchronization for your_user
     Loaded: loaded (/usr/lib/systemd/system/[email protected]; enabled; preset: enabled)
     Active: active (running) since ...

On first start Syncthing generates its keys, certificate and configuration in ~/.local/state/syncthing/ (older installs may use ~/.config/syncthing/). Confirm which ports it is listening on:

sudo ss -tulpn | grep syncthing
udp   UNCONN 0  0        0.0.0.0:21027   0.0.0.0:*   users:(("syncthing",...))
udp   UNCONN 0  0              *:22000         *:*   users:(("syncthing",...))
tcp   LISTEN 0  4096   127.0.0.1:8384    0.0.0.0:*   users:(("syncthing",...))
tcp   LISTEN 0  4096           *:22000         *:*   users:(("syncthing",...))

The web GUI on port 8384 is bound to 127.0.0.1, so it is not reachable from the internet. Keep it that way.

If the service does not start, read its log:

journalctl -u syncthing@your_user.service -n 50 --no-pager

Step 4 - Opening the firewall

Other devices must reach port 22000 to connect directly. Local discovery on port 21027 only matters when devices share a LAN, but opening it does no harm:

sudo ufw allow 22000/tcp
sudo ufw allow 22000/udp
sudo ufw allow 21027/udp

Verify the rules:

sudo ufw status
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
22000/tcp                  ALLOW       Anywhere
22000/udp                  ALLOW       Anywhere
21027/udp                  ALLOW       Anywhere

Do not open port 8384. If devices cannot connect directly (for example, one of them is behind NAT without a public port), Syncthing falls back to the public relay pool automatically. Data through relays remains end-to-end encrypted.

Step 5 - Accessing the web GUI through an SSH tunnel

Instead of exposing the GUI, forward it to your local machine over SSH. Run this on your local computer, replacing your_server_ip:

ssh -L 8385:127.0.0.1:8384 your_user@your_server_ip

Local port 8385 is used so it does not clash with a Syncthing instance already running on your computer. Leave the session open and browse to http://127.0.0.1:8385.

The GUI shows a warning that no GUI password is set. Fix that first:

  1. Open Actions > Settings > GUI.
  2. Set a GUI Authentication User and a strong GUI Authentication Password.
  3. Click Save.

The page reloads and asks you to log in. Anyone with shell access to the server could otherwise reach the GUI on localhost, so the password matters even behind the tunnel.

Step 6 - Pairing a second device

Every Syncthing instance has a unique Device ID derived from its certificate. Devices only talk to peers whose ID they have explicitly accepted.

On the server GUI, open Actions > Show ID and copy the ID. It looks like this:

MFZWI3D-BONSGYC-YLTMRWG-C43ENR5-QXGZDMM-FZWI3DP-BONSGYY-LTMRWAD

On your second device:

  1. Open its Syncthing GUI and click Add Remote Device.
  2. Paste the server's Device ID and give it a name such as cubepath-server.
  3. Leave Addresses as dynamic (or set tcp://your_server_ip:22000 to skip discovery) and click Save.

Within about a minute the server GUI shows a banner saying that the new device wants to connect. Click Add Device, check the name and click Save.

To verify, look at the Remote Devices panel on either side. The peer should show Up to Date or Connected, along with its address. An address like tcp://203.0.113.10:22000 or quic://... means a direct connection. relay://... means the connection goes through a relay, which usually indicates port 22000 is blocked somewhere.

Step 7 - Sharing a folder

Create a directory on the server to hold the synced data:

mkdir -p ~/Sync/documents

In the server GUI click Add Folder and fill in the tabs:

  • General: set Folder Label to Documents and Folder Path to ~/Sync/documents. Note the generated Folder ID; both sides must use the same ID.
  • Sharing: tick the second device.
  • Advanced: choose the Folder Type.

The folder type controls the direction of changes:

Folder typeBehaviorTypical use
Send & ReceiveChanges flow both waysWorking files shared between devices
Send OnlyLocal changes are sent, remote changes are ignoredSource of truth, such as a laptop being backed up
Receive OnlyRemote changes are applied, local changes are not sentBackup copy on a server
Receive EncryptedStores only encrypted dataUntrusted host that should never see file contents

Click Save. The second device shows a prompt to accept the shared folder; accept it and choose a local path.

To share with an untrusted server, set an encryption password for that device in the Sharing tab on the trusted side. The untrusted device must accept the folder as Receive Encrypted, and it stores file names and contents encrypted.

Verify the sync by creating a file on the server:

echo "hello from the server" > ~/Sync/documents/test.txt

After a few seconds the file appears on the second device, and the folder shows Up to Date in both GUIs.

Step 8 - Enabling file versioning

By default Syncthing overwrites or deletes files when a peer changes them. Versioning keeps the old copy in a .stversions directory inside the folder on the device that receives the change.

Edit the folder, open the File Versioning tab and pick a strategy:

StrategyWhat it keeps
Trash CanDeleted or replaced files, removed after a number of days you set
SimpleThe last N versions of each file
StaggeredVersions thinned over time: one per 30 seconds for the first hour, one per hour for the first day, one per day for 30 days, then one per week up to a maximum age
ExternalHands the file to a command of your choice

Staggered with a maximum age of 365 days is a good default for documents. Save the folder and test it by editing test.txt on the second device, then list the versions on the server:

ls -la ~/Sync/documents/.stversions/
-rw-rw-r-- 1 your_user your_user 22 ... test~20260925-101512.txt

Versioning is not a backup: it only protects against changes that arrive from other devices, and it lives on the same disk.

If two devices edit the same file before syncing, Syncthing keeps both and renames the losing copy to test.sync-conflict-<date>-<time>-<device>.txt. Compare the files and delete the one you do not need.

Step 9 - Excluding files with .stignore

Create a .stignore file in the root of the synced folder to skip caches and build output. The file is not synced itself, so create it on each device that needs it:

nano ~/Sync/documents/.stignore
// Operating system clutter
(?d).DS_Store
(?d)Thumbs.db

// Editor and temporary files
*.swp
*.tmp
*~

// Keep this one directory even though node_modules is ignored below
!/important/node_modules

// Dependency and build directories
node_modules
__pycache__
/build

The rules work like this:

  • // starts a comment.
  • A pattern without a leading / matches at any depth, and /build matches only at the folder root.
  • ! includes a path again. The first matching line wins, so put exceptions before the broader pattern.
  • (?d) lets Syncthing delete the ignored file if it blocks the removal of a directory that was deleted on another device.

Syncthing reloads the file on the next scan. Verify it by opening Edit > Ignore Patterns on the folder in the GUI, which shows the active rules.

Troubleshooting

The peer stays "Disconnected". Check that both sides have added each other's Device ID and that port 22000 is reachable from the other device:

nc -vz your_server_ip 22000

A succeeded result means the port is open. If it times out, check sudo ufw status on the server and any provider or router firewall in between.

"Failed to start filesystem watcher" or inotify errors in the log. Large folders can exceed the kernel's limit on inotify watches. Raise it permanently:

echo "fs.inotify.max_user_watches=204800" | sudo tee /etc/sysctl.d/90-syncthing-inotify.conf
sudo sysctl --system

Then restart the service with sudo systemctl restart syncthing@your_user.service.

Permission denied on synced files. Syncthing runs as your_user and can only read and write what that user owns. Fix ownership of the folder with sudo chown -R your_user:your_user ~/Sync.

Conclusion

You now have Syncthing running as a systemd service on Ubuntu 24.04, with the GUI protected behind a password and an SSH tunnel, a paired device, and a shared folder with versioning and ignore rules. As next steps, you can add a third device and share the same folder to build a small mesh, use a Receive Only folder on the server as an always-on copy of your laptop, and combine it with a real backup tool such as restic or BorgBackup for off-site history.