Applies to: Syncthing 2.1.5 in the official syncthing/syncthing Docker image, Docker Compose v2; tested in Docker (arm64)
Syncthing keeps folders in sync between your devices without a cloud service in the middle. To run it on a Linux server with Docker, use the official syncthing/syncthing image with a Compose file, keep the web interface on localhost, reach it through an SSH tunnel, and open port 22000 (TCP and UDP) for the sync traffic.
1. Create the Compose file
You need Docker with the Compose plugin (see install Docker on Debian and Ubuntu). Create a folder such as /opt/syncthing and save this as compose.yaml:
services:
syncthing:
image: syncthing/syncthing
container_name: syncthing
hostname: my-syncthing
environment:
- PUID=1000
- PGID=1000
- STGUIADDRESS=
volumes:
- /srv/syncthing:/var/syncthing
network_mode: host
restart: unless-stopped
PUIDandPGID: the user and group Syncthing runs as (1000 by default). Synced files on the server belong to this user, so set your own user’s IDs (id -uandid -g)./var/syncthing: the image keeps its configuration in/var/syncthing/configand your synced folders go below/var/syncthing. Here they are stored in/srv/syncthingon the server. The image makes/var/syncthingitself owned by that user when it starts. Mount more host folders the same way, for example/srv/share:/var/syncthing/share, and make sure that user can write to them (sudo chown -R 1000:1000 /srv/share).STGUIADDRESS=(empty): without it the image listens on0.0.0.0:8384, open to anyone who can reach the port. Empty, Syncthing uses the address from its configuration, which is127.0.0.1:8384on a new install.network_mode: host: Syncthing’s own documentation recommends host networking, because in Docker’s default bridge network Syncthing only sees the container’s internal IP address.hostname: becomes the device name that other devices see.
2. Start it
docker compose up -d docker logs syncthing
In our test the log showed the version, the device ID and the listeners:
INF syncthing v2.1.5 "Hafnium Hornet" (go1.27.1 linux-arm64) ... [noupgrade] INF Calculated our device ID (device=ATOKJNF-CFBR5YA-DUSC3DW-NBAUSDQ-VV6V3ZX-BYR3LK2-XFL3FQ7-YONCDAX ...) INF GUI and API listening (address=127.0.0.1:8384 log.pkg=api) INF QUIC listener starting (address="[::]:22000" log.pkg=connections) INF TCP listener starting (address="[::]:22000" log.pkg=connections)
After about a minute, docker ps shows (healthy): the image has a built-in health check that calls /rest/noauth/health. You can print the device ID at any time with docker exec syncthing syncthing device-id.
3. Open the web interface through SSH
On your own computer, open a tunnel to the server and leave it running:
ssh -L 8384:127.0.0.1:8384 user@your-server-ip
Then browse to http://127.0.0.1:8384. The interface shows a Danger! banner asking you to set a GUI Authentication User and Password. Do it under Actions > Settings > GUI: fill in GUI Authentication User and GUI Authentication Password and save. If you ever make the interface reachable from outside, also tick Use HTTPS for GUI.
4. Open the sync port
Devices connect to each other on port 22000, TCP and UDP (QUIC). Port 21027/UDP is only for finding devices on the same local network, so a VPS doesn’t need it. With UFW:
sudo ufw allow 22000/tcp sudo ufw allow 22000/udp
Without an open port, devices may still reach each other through Syncthing’s public relays, but according to Syncthing’s firewall guide that performs poorly compared with a direct connection. More on rules in UFW on Ubuntu.
5. Connect a device and share a folder
- In the server’s interface click Actions > Show ID and copy the device ID.
- On your computer, in Syncthing, click Add Remote Device and paste it into Device ID. The server then shows a message that the new device wants to connect; click Add Device there.
- Click Add Folder on one side, choose a path (on the server, one below
/var/syncthing, such as/var/syncthing/documents), and tick the other device on the Sharing tab.
Updating
The Docker image has Syncthing’s automatic upgrade switched off (the log line ends in [noupgrade]). Update by pulling a new image:
docker compose pull docker compose up -d
Without host networking
If you prefer the bridge network, remove network_mode: host and publish the ports instead, keeping the interface on localhost:
ports:
- 127.0.0.1:8384:8384
- 22000:22000/tcp
- 22000:22000/udp
In that case also remove STGUIADDRESS=, so the interface listens inside the container and the 127.0.0.1 mapping keeps it private. Note that ports published by Docker are not filtered by UFW.
Related: list and remove Docker containers and volumes and run Jellyfin in Docker on a VPS. For a server to sync to, a KVM VPS with full root access works well.
Official documentation: Syncthing Docker README and Docker packet filtering and firewalls.