Setting up a Syncthing file synchronization server in docker
Greetings!

In this article I’ll show how to easily deploy your own instance of a Syncthing server using docker compose🐳 on a system running Linux🐧. And of course I’ll go into detail about connecting clients, using Linux Mint, Windows, and Android as examples.

For those who don’t know, Syncthing is a popular client-server open source solution for synchronizing files🗃 between different devices📱💻.

Preface

This article is part of a series about setting up personal infrastructure☝️. Here’s what we’ve already installed and configured in previous entries:

Today, a Syncthing server will be added to our little infrastructure✅. The resulting scheme will look like this:

Introduction

Most often I deploy my services in a distribution environment based on Debian. Today’s case is no exception — the demonstration will be carried out on Debian 12🔥.

As already mentioned, Syncthing is software for synchronizing files between different devices. Here are the main points from the developers:

The project is written in Go and distributed under the open MPL-2.0 license.

For a better understanding of what follows, let me list the main entities of the Syncthing service📋:

This article describes a way to set up centralized file synchronization using your own server, which will act as a hub for external devices such as a smartphone, laptop, PC, etc.

It’s worth warning right away that, by default, Syncthing uses both local discovery and global discovery via a network of public servers, the list and status of which you can view here. This means devices connected to Syncthing will be able to exchange files from anywhere in the world.

For users who prefer more privacy — at the end of the article there’s an example of setting up file synchronization only within an internal network, such as a VPN. This method is less convenient, but more private.

Preparation

To set up our own Syncthing service, we’ll need a Linux server with docker engine installed and running. If you don’t have your own server yet, the following articles might be helpful:

If the Linux server is ready, connect to it, for example, via SSH🔐, and first install the git version control system:

BASH
sudo apt update && sudo apt install -y git
Click to expand and view more

Next, download the project files from my GitHub into the /opt directory:

BASH
sudo git clone https://github.com/r4ven-me/syncthing /opt/syncthing
Click to expand and view more

File listing:

Note that the syncthing service described in the docker-compose.yml file is intentionally limited in hardware resource usage to cpus: '0.70' and memory: 512M, i.e., the maximum allowed usage is 70% of one core and 512 MB of RAM. Adjust these parameters as needed for your own use case. Read more about resource limits for services when using docker-compose here.

Now let’s create the service group and user syncthing for running the service:

BASH
sudo addgroup --system --gid 3113 syncthing

sudo adduser --system --gecos "Syncthing file synchronization system" \
    --disabled-password --uid 3113 --ingroup syncthing  \
    --shell /sbin/nologin --home /opt/syncthing/data syncthing
Click to expand and view more

Don’t forget to set restricted permissions on the directory☝️ where our files will be stored:

BASH
sudo chmod 700 /opt/syncthing/data
Click to expand and view more

For more on file permissions, see a separate article.

Let’s check that all the required files and folders are present:

BASH
sudo ls -l /opt/syncthing
Click to expand and view more

Great, let’s move on 🚶.

Starting the Syncthing server with docker compose

Let’s check the syntax of the compose file and bring up our new service:

BASH
sudo docker compose -f /opt/syncthing/docker-compose.yml config --quiet

sudo docker compose -f /opt/syncthing/docker-compose.yml up -d

sudo docker ps
Click to expand and view more

Yep, great. Let’s check the container output:

BASH
sudo docker logs -f syncthing
Click to expand and view more

Should look something like this:

All good👌.

Setting up autostart with systemd

At the beginning of the article we created the service user syncthing. We’ll use it to securely run our new service via sudo💪.

Copy the file describing the restricted sudoers permissions for the syncthing user, first checking it for syntax errors:

BASH
sudo visudo --check --file=/opt/syncthing/syncthing_sudoers

sudo cp /opt/syncthing/syncthing_sudoers /etc/sudoers.d/
Click to expand and view more

The syncthing_sudoers file describes privileges📝 that allow the syncthing user to start and stop the services described in our docker-compose.yml, on behalf of the privileged docker group via sudo. These are exactly the commands that will be used in the systemd service unit.

I recently looked into the intricacies of the privilege escalation mechanism in Linux. For a better understanding, I recommend reading this article: Linux command line, privilege escalation: su, sudo commands 😌.

Now let’s also check, then copy the systemd service file and reload the configuration:

BASH
sudo systemd-analyze verify /opt/syncthing/syncthing.service

sudo cp /opt/syncthing/syncthing.service /etc/systemd/system/

sudo systemctl daemon-reload
Click to expand and view more

The syncthing.service file describes the startup🛠 conditions for the syncthing container, such as: checking that the docker daemon is running, restarting the service on failure (with a 5-sec. interval), determining the user/group under which the service should run, and the actual start/stop commands for this service.

Stop the container we started manually earlier, and start it via systemd instead + enable the service to autostart at system boot:

BASH
sudo docker compose -f /opt/syncthing/docker-compose.yml down

sudo systemctl enable --now syncthing
Click to expand and view more

Check the status:

BASH
sudo systemctl status syncthing
Click to expand and view more

Should look like this:

The server is up and running😎!

Configuring the Syncthing server via the web interface

In my example, for security reasons, Syncthing was set up on the local interface with address 127.0.0.1. If you’re setting up the service on a remote machine, then to access the Syncthing web interface run the following SSH command on the client machine to forward the needed port (8384):

BASH
ssh -N -f -L 7777:127.0.0.1:8384 user@example.com
Click to expand and view more

Where (in order):

In my example, the command looks like this:

Now open a web browser and go to:

BASH
http://127.0.0.1:7777
Click to expand and view more

First we’re greeted with a question about sending anonymous reports. I’ll leave that up to you😉.

Next, we’re notified that logging into the control panel is done without a password and that this is unsafe😳.

So let’s go into the settings and create a new user there and set a password for them:

This is done on the “Interface” tab:

Don’t forget to click “Save”. After this, the service will restart and we’ll be kindly asked to log in with the new credentials:

The main Syncthing management menu will open in front of us🧑‍💻.

By default, the server already uses one directory, “Default folder”, located at:

Installing and connecting clients

Syncthing clients exist for all popular platforms💻📱. You can find the full list here and here😇.

Under the hood, clients run the Syncthing backend (similar to the server) plus a graphical frontend + a system tray icon. By default, the service also listens for web connections🌐, so you can always connect to it via a browser (this feature can be disabled if desired). The listening port depends on the client. Most often it’s 8080 or 8384🤷‍♂️.

Next I’ll show the client connection process using Linux Mint 22, Windows 10, and Android 13🫡 as examples.

Recommendation: during the initial client setup, use directories without important files to minimize risks in case of any mistakes.

Linux Mint

Open a terminal, update the package cache, and install the Syncthing graphical client with system tray support from the standard repositories:

BASH
sudo apt update && sudo apt install -y syncthing-gtk
Click to expand and view more

There’s also a qt version.

After installation, launch the program from the main menu:

Let’s go straight to the settings and enable Syncthing autostart🚀 when the user’s graphical session starts:

Enable these checkboxes and click “Save”:

A default synchronization directory is created by default. Delete it so there’s no confusion when we add the centralized folder:

Now we need to find out our client ID. This is done here:

Copy it, then go back to the server’s control panel and add a new device:

Paste the ID on the “General” tab and specify a device name if needed:

Then go to the “Sharing” tab and check the box to share the directory on the server:

After clicking “Save”, after a while the client should receive two requests:

1. A request to add a device (the server):

2. A request to add a shared directory:

Here we specify the path to the local folder we’ll be syncing, and also uncheck the “Receive Only Folder” checkbox:

Be sure to wait for and accept both requests!

That’s it, the first client is ready:

Linux Mint client

Syncthing server

At this point, we have synchronization configured for the directories:

Let’s check that synchronization works🛠. As an example, let’s create 20 empty files on the server with this command:

BASH
sudo -u syncthing touch /opt/syncthing/data/Sync/test_file{1..20}.txt
Click to expand and view more

The files appeared on the client and a notification arrived:

Now if we delete all the files but one in the file manager:

They will also be deleted on the server✍️. Synchronization is configured😌.

Important! In the main synchronized directory (on both the client and the server), there’s a hidden service folder .stfolder. Don’t delete it, otherwise synchronization will break and you’ll have to reconnect everything from scratch.

To avoid turning this article into a wall of text📜 (although it’s already too late🙃), I’ve hidden the client setup steps for Windows and Android under spoilers. Just click on them if needed.

Windows

Android

Optional

Setting up Syncthing to work only within an internal network

If you’re deploying the Syncthing server within an internal network, for example a VPN, then specify the address of the VPN virtual interface as the IP address for accepting connections.

Server setup

To do this, edit the docker-compose.yml file:

BASH
sudo nvim /opt/syncthing/docker-compose.yml
Click to expand and view more

Replace 192.168.122.233 with your own address.

And restart the server:

BASH
sudo systemctl restart syncthing
Click to expand and view more

After that, go to the server settings in the web interface using the new address (for me it’s http://192.168.122.233:8384:

Next, go to the “Connections” tab. In the “Sync Protocol Listen Addresses” field, the default value is default, which includes a whole list of addresses, including the public relay servers of the Syncthing project:

BASH
tcp://0.0.0.0:22000, quic://0.0.0.0:22000 and dynamic+https://relays.syncthing.net/endpoint
Click to expand and view more

Change it to a single value:

BASH
tcp://0.0.0.0:22000
Click to expand and view more

Also on this tab, disable the unnecessary options, except for local discovery:

Now the server will only accept connections on the container’s address, in my example that’s 192.168.122.233:22000, and won’t use the public servers.

Why did we specify 0.0.0.0 above instead of 192.168.122.233? Because 0.0.0.0 in this case is the address (i.e., all addresses) for listening inside the container itself; we previously set up access to the container via 192.168.122.233. So going forward, this is the exact address that needs to be specified on the clients🤯.

Client setup

Now on the client, explicitly specify the address for connecting to the server. In the case of Linux Mint, this is done like this:

Done.

Change the settings on the other clients in the same way🫠.

Setting up direct client connections via public Syncthing relay servers

Earlier we described a way to centralize file synchronization using our own server, which is always online.

But the Syncthing service also provides the ability to transfer files directly, from one device to another, using the public relay servers of the Syncthing project as intermediaries.

The connection is set up similarly to the server case, just without the server😁.

Here’s a rough algorithm:

  1. Copy the Android client ID;
  2. Open Syncthing on Windows;
  3. Click “Add Device”, enter the ID from Android there, and select the directory to synchronize;
  4. After a while, two requests will appear in the notification shade on the Android client:
    • Add new device;
    • Add the shared folder from this device.

Since device connections happen through public relays, synchronization will happen whenever both devices are simply connected to the internet from anywhere. In certain cases, this solution can be useful😉.

Conclusion

To sum up: we got a functional and easily portable file synchronization system project, running inside a docker container, with autostart configured via systemd. We also went through the client connection process for different platforms😎.

I’ve been actively using this service for several years now within my VPN network. It’s very convenient for storing various files this way, especially the encrypted password database file KeePass, which I can read/edit on any device without fear of losing anything.

Sources used

Copyright Notice

Author: Ivan Cherniy

Link: https://r4ven.me/en/storage/podnimaem-server-sinhronizacii-fajlov-syncthing-v-docker/

License: CC BY-NC-SA 4.0

Blog materials may be used with attribution to the author and source, for non-commercial purposes, and under the same license.

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut