Syncthing + Tailscale + Synology DSM
Following the trend of self-hosting more software in response to the instability of today’s tech industry, I thought of trying Syncthing, “an application that lets you synchronize your files across multiple devices”.
I want to run Syncthing in my Tailscale tailnet and for the occasion I thought of trying to run Docker on my Synology NAS, which is something I haven’t tried before; the alternative would have been to run Syncthing in one of my homelab servers and mount remotely a directory from the NAS.
For some reason, Docker in DSN is called Container Manager, so that’s the first thing to install and setup; in my case the only setup needed was to create a dedicated directory in the NAS and assign it to Container Manager during the installation.
Let’s say this directory is /volume1/docker
.
Now we need to create a few directories for Syncthing:
/volume1/docker/syncthing
/volume1/docker/syncthing/data
/volume1/docker/syncthing/tailscale
/volume1/docker/syncthing/tailscale-serve
Next we need to create a serve.json
file with the following contents and upload it to /volume1/docker/syncthing/tailscale-serve
:
{
"TCP": {
"443": {
"HTTPS": true
}
},
"Web": {
"syncthing.my-tailnet.ts.net:443": {
"Handlers": {
"/": {
"Proxy": "http://127.0.0.1:8384"
}
}
}
}
}
Remember to change syncthing.my-tailnet.ts.net
with the name you decided to assign to your tailnet
node and your tailnet domain.
Next we need to create the compose file for Syncthing, that will later be used to setup the containers in Container Manager:
---
services:
syncthing:
image: "syncthing/syncthing:1.29"
container_name: "syncthing"
restart: "unless-stopped"
volumes:
- "/volume1/docker/syncthing/data:/var/syncthing"
# ports:
# - "8384:8384"
# - "22000:22000/tcp"
# - "22000:22000/udp"
# - "21027:21027/udp"
environment:
- TZ=UTC
- PUID=1030
- PGID=100
depends_on:
- tailscale
network_mode: service:tailscale
tailscale:
image: "tailscale/tailscale:latest"
container_name: "syncthing-tailscale"
hostname: "syncthing"
environment:
- TS_AUTHKEY=tskey-auth-foo-bar-baz
# - TS_EXTRA_ARGS=--advertise-tags=tag:syncthing
- TS_STATE_DIR=/var/lib/tailscale
- TS_USERSPACE=false
- TS_SERVE_CONFIG=/serve-config/serve.json
volumes:
- "/volume1/docker/syncthing/tailscale:/var/lib/tailscale"
- "/volume1/docker/syncthing/tailscale-serve:/serve-config"
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
restart: unless-stopped
Few things need to be changed here; in syncthing
’s service definition:
- the volume’s path to match the directory you created in the previous step
- the
TZ
environment variable if you want to use local time PUID
andPGID
should match your user’s uid and gid in the NAS; log in via SSH and runid
to find yours
In tailscale
’s service definition:
- the
hostname
, which will determine the name of this node in your tailnet - the
TS_AUTHKEY
environment variable with a valid auth key for your tailnet - the
TS_EXTRA_ARGS
environment variable in case you want to pass Tailscale extra parameters, for example to advertise a specific tag - the two volumes’ paths to match the directories created in the previous step
Also note that I specified a tag for synchting’s docker image (syncthing/syncthing:1.29
), but you
may want to use latest
instead. I prefer to upgrade software in a controlled manner, when I have
time to do it properly.
The ports
section is intentionally commented out: we don’t need to expose any port here, but it’s
good to have a reference of the ports used by Syncthing.
Now you can create a new project in Container Manager, paste the compose file we just created, build
and start the containers. Syncthing should be available on your tailnet as
https://syncthing.my-tailnet.ts.net
(once again replace with your node’s name and tailnet’s
domain). It might take a few seconds to load the first time, due to the automatic provisioning of
the TLS certificate via Let’s Encrypt.
Your Syncthing installation should now be fully functional and reachable by other clients via Tailscale.
Now, I’m still figuring out this part, but:
- Syncthing by default tries to open ports via UPnP on your firewall.
- Syncthing enable Global Discovery by default, registering your node to a public database.
- Syncthing, I think, will try to determine your public address (i.e. the address used by another nodes to reach it), to use as “Sync Protocol Listen Addresses”.
As this installation is meant to only exist within my VPN I’m changing a few settings in the “Connections” tab:
- Sync Protocol Listen Addresses:
tcp4://100.x.y.z:22000, quic://100.x.y.z.:22000
(use your node’s tailnet IP) - Enable NAT traversal: disabled
- Global Discovery: disabled
I’m not entirely sure about the “Sync Protocol Listen Addresses”, because if Syncthing starts before
Tailscale is fully connected it might fail to bind to those IP; restart: "unless-stopped"
should
take care of restarting it until Tailscale is fully connected, but I haven’t tested this yet.
Since we turned off Global Discovery, when we try to add a new client to Syncthing we’ll need to
specify the address by hand, using something like tcp4://100.x.y.z:22000
or
quic://100.x.y.z.:22000
; I don’t know what works best and if Syncthing tries to use both even if
you only specify one, so maybe start with the quic://
address first.