Syncthing synchronise des fichiers en continu, chiffré, et en pair-à-pair entre vos machines, sans passer par un cloud ni un serveur central tiers. C'est un des projets auto-hébergés les plus populaires (plus de 85 000 étoiles GitHub), toujours très actif : la version v2.1.1 date de juin 2026, après une v2 majeure qui a remplacé le moteur de base de données LevelDB par SQLite.
Ce guide déroule un cas d'usage homelab concret : garder un dossier de notes et de configuration synchronisé en temps réel entre un laptop de dev et un serveur homelab qui sert de point central. On pilote tout en CLI et API, pas par la Web GUI, pour un déploiement reproductible et scriptable.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Déployer deux nœuds Syncthing v2 avec Docker.
- Appairer les devices et partager un dossier entièrement en ligne de commande.
- Configurer un hub
receive-onlyavec versioning trashcan comme filet de sécurité. - Piloter l'instance par l'API REST.
- Situer Syncthing par rapport à rsync et éviter les pièges classiques.
Prérequis
Section intitulée « Prérequis »- Une machine avec Docker et Docker Compose (le lab tourne sur un seul hôte pour simuler deux machines).
- Des bases de ligne de commande Linux et de réseau (ports, TLS).
- Aucun compte ni service tiers : Syncthing fonctionne sans inscription.
Syncthing en bref
Section intitulée « Syncthing en bref »Avant de lancer les commandes, quelques notions structurantes. Les comprendre évite les mauvaises surprises, car un mauvais type de dossier peut propager une suppression là où vous ne l'attendiez pas.
- Device ID : identifiant unique dérivé de l'empreinte du certificat TLS de chaque nœud. Deux nœuds ne se parlent que si chacun connaît le Device ID de l'autre : c'est l'appairage.
- Type de dossier :
sendreceive(envoie et reçoit, le mode courant),sendonly(source qui n'accepte aucune modification distante),receiveonly(miroir qui applique les changements du cluster mais ne repousse jamais ses propres modifications) etreceiveencrypted(nœud non fiable qui ne stocke que du chiffré). - Versioning : que faire d'un fichier supprimé ou remplacé.
trashcanle déplace dans.stversions,simplegarde N versions horodatées,staggeredespace les versions dans le temps. - Découverte et relais : les nœuds se trouvent par découverte locale (broadcast LAN) ou globale (annuaire public), et communiquent en direct sur le port 22000. Derrière un NAT strict, ils retombent sur des relais publics, plus lents mais toujours chiffrés.
Le montage homelab : un laptop et un hub
Section intitulée « Le montage homelab : un laptop et un hub »Notre topologie est celle qui revient le plus souvent en homelab : un hub always-on (le serveur) auquel les appareils s'appairent. Le laptop est en sendreceive, le hub en receiveonly : ainsi, une modification faite par erreur sur le hub ne remonte jamais écraser l'original du laptop.
Le fichier compose.yaml déclare deux nœuds sur un même réseau Docker :
services: laptop: image: syncthing/syncthing:latest container_name: st-laptop hostname: laptop environment: - STGUIADDRESS=0.0.0.0:8384 # exposer l'API REST pour piloter sans GUI - PUID=1000 - PGID=1000 volumes: - ./laptop:/var/syncthing ports: - "8384:8384" networks: [labnet]
hub: image: syncthing/syncthing:latest container_name: st-hub hostname: hub environment: - STGUIADDRESS=0.0.0.0:8384 - PUID=1000 - PGID=1000 volumes: - ./hub:/var/syncthing ports: - "8385:8384" networks: [labnet]
networks: labnet:Au premier démarrage, chaque nœud génère son certificat, son Device ID et son config.xml :
mkdir -p laptop hubdocker compose up -ddocker exec st-laptop syncthing --version# syncthing v2.1.1 "Hafnium Hornet" (go1.26.3 linux-amd64) [noupgrade]Appairer les deux nœuds en CLI
Section intitulée « Appairer les deux nœuds en CLI »La sous-commande syncthing cli enveloppe l'API REST : elle a besoin de l'adresse du GUI et de la clé API de l'instance visée. On récupère d'abord les deux Device ID et les deux clés API dans les config.xml (montés côté hôte) :
LID=$(sed -n 's:.*device id="\([A-Z0-9-]*\)".*:\1:p' laptop/config/config.xml | head -1)HID=$(sed -n 's:.*device id="\([A-Z0-9-]*\)".*:\1:p' hub/config/config.xml | head -1)LKEY=$(sed -n 's:.*<apikey>\(.*\)</apikey>.*:\1:p' laptop/config/config.xml)HKEY=$(sed -n 's:.*<apikey>\(.*\)</apikey>.*:\1:p' hub/config/config.xml)echo "laptop=$LID"echo "hub=$HID"# laptop=DG3QUWH-FSEGGBW-HPZG6BF-WYCCEA6-Z4UN4T6-WSBDY4O-2KGBFO4-HH2CBQP# hub=GK752H4-WIVWBKG-2S54EUS-NIMPZXZ-M6DBMPM-GSESELR-FGCEWG4-XCE7WACOn déclare ensuite chaque nœud chez l'autre, en fixant l'adresse directe du pair (ici son nom de conteneur) :
lcli(){ docker exec st-laptop syncthing cli --gui-address http://127.0.0.1:8384 --gui-apikey "$LKEY" "$@"; }hcli(){ docker exec st-hub syncthing cli --gui-address http://127.0.0.1:8384 --gui-apikey "$HKEY" "$@"; }
lcli config devices add --device-id "$HID" --name hub --addresses "tcp://hub:22000"hcli config devices add --device-id "$LID" --name laptop --addresses "tcp://laptop:22000"Quelques secondes plus tard, la connexion directe est établie en TLS 1.3 :
lcli show connections# "connected": true,# "address": "172.27.0.3:22000",# "clientVersion": "v2.1.1",# "crypto": "TLS1.3-TLS_AES_128_GCM_SHA256",# "type": "tcp-client"Partager un dossier : laptop en source, hub en miroir
Section intitulée « Partager un dossier : laptop en source, hub en miroir »On crée le dossier vault en sendreceive sur le laptop, on le partage avec le hub, puis on l'ajoute sur le hub en receiveonly :
lcli config folders add --id vault --label "Vault de notes" --path /var/syncthing/vaultlcli config folders vault devices add --device-id "$HID"
hcli config folders add --id vault --label "Vault (hub)" --path /var/syncthing/vault --type receiveonlyhcli config folders vault devices add --device-id "$LID"
hcli config folders vault type get# receiveonlyLe filet de sécurité se règle par l'API REST, avec un PATCH sur le dossier du hub pour activer le versioning trashcan :
curl -s -X PATCH -H "X-API-Key: $HKEY" \ -d '{"versioning":{"type":"trashcan","params":{"cleanoutDays":"15"}}}' \ http://localhost:8385/rest/config/folders/vaultVérifier la synchronisation
Section intitulée « Vérifier la synchronisation »On écrit un fichier côté laptop, on déclenche un scan (utile quand inotify n'a pas encore réagi), et on observe la complétion vue par le hub :
docker exec st-laptop sh -c 'echo "# Notes homelab" > /var/syncthing/vault/notes.md'curl -s -X POST -H "X-API-Key: $LKEY" "http://localhost:8384/rest/db/scan?folder=vault"
curl -s -H "X-API-Key: $HKEY" "http://localhost:8385/rest/db/completion?folder=vault"# { "completion": 100, "globalItems": 1, "needItems": 0, "needBytes": 0 }
docker exec st-hub sh -c 'ls -l /var/syncthing/vault'# -rw-r--r-- 1 1000 1000 47 notes.mdLe fichier est arrivé sur le hub, et son propriétaire est bien l'UID 1000 : la configuration PUID est respectée.
Le filet de sécurité : la suppression et le trashcan
Section intitulée « Le filet de sécurité : la suppression et le trashcan »C'est le test qui montre à la fois la limite et la parade. On supprime le fichier sur le laptop. La suppression se propage au hub, comme prévu. Mais parce que le hub porte un versioning trashcan, le fichier n'est pas perdu : il atterrit dans .stversions.
docker exec st-laptop rm /var/syncthing/vault/notes.mdcurl -s -X POST -H "X-API-Key: $LKEY" "http://localhost:8384/rest/db/scan?folder=vault"
docker exec st-hub sh -c 'ls -A /var/syncthing/vault'# .stfolder .stversions <- notes.md a disparu du dossier courant
docker exec st-hub sh -c 'ls -l /var/syncthing/vault/.stversions'# -rw-r--r-- 1 1000 1000 47 notes.md <- récupérable iciSans versioning, ce fichier serait définitivement effacé partout. C'est exactement pour cela que le hub est en receiveonly et en trashcan : deux garde-fous contre une fausse manipulation.
Piloter par l'API REST
Section intitulée « Piloter par l'API REST »Tout ce que fait la Web GUI passe par l'API REST, sur le port du GUI, préfixe /rest/, avec le header X-API-Key. La clé se lit dans config.xml (balise apikey). Quelques points d'entrée utiles :
curl -H "X-API-Key: $HKEY" http://localhost:8385/rest/system/status # état du nœudcurl -H "X-API-Key: $HKEY" http://localhost:8385/rest/config # config complètecurl -H "X-API-Key: $HKEY" http://localhost:8385/rest/db/status?folder=vaultPour un serveur, préférez syncthing cli config ... : la commande construit le bon payload et évite les erreurs de JSON à la main.
Installation hors Docker
Section intitulée « Installation hors Docker »Sur une vraie machine (le laptop, ou le serveur homelab en natif), utilisez le dépôt APT signé officiel, canal stable-v2, puis le service systemd par utilisateur. Aucun curl | sh : on télécharge la clé dans un fichier et on l'utilise avec signed-by.
sudo mkdir -p /etc/apt/keyringssudo curl -L -o /etc/apt/keyrings/syncthing-archive-keyring.gpg \ https://syncthing.net/release-key.gpg
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
sudo apt-get update && sudo apt-get install syncthing# Service système attaché à un utilisateur dédié, démarre au bootsudo systemctl enable --now syncthing@monuser.servicesystemctl status syncthing@monuser.serviceLe template syncthing@user fait tourner le démon sous le compte cité, jamais sous root.
Sécurité
Section intitulée « Sécurité »- Chiffrement de bout en bout : tout le trafic entre nœuds est en TLS, l'authentification repose sur l'empreinte du certificat (le Device ID). Un nœud inconnu ne peut pas rejoindre le cluster.
- GUI en local : par défaut l'interface n'écoute que sur
localhost. Si vous l'exposez, protégez-la par utilisateur et mot de passe (haché en bcrypt dansconfig.xml) et activez le TLS. - Nœud non fiable (receive-encrypted) : vous pouvez stocker une copie chiffrée sur un VPS bon marché sans lui confier les clés de déchiffrement. Le nœud distant ne voit que du chiffré (métadonnées comme la taille approximative restent visibles).
- Moindre privilège : protégez
config.xmlet les clés TLS. Quiconque y accède peut usurper votre device. Un utilisateur système dédié viasyncthing@userlimite la casse.
Syncthing n'est pas un backup
Section intitulée « Syncthing n'est pas un backup »Le point à ne jamais oublier. Syncthing propage l'état d'un dossier ; il ne garde pas d'historique profond et ne protège pas contre une corruption répliquée. Le pattern homelab qui fait consensus est clair :
- Syncthing pour propager en temps réel entre appareils.
- Un vrai outil de sauvegarde versionnée derrière, côté hub : un rsync planifié vers un stockage distant, un Rclone vers un bucket, ou des snapshots (Btrfs/ZFS) du dossier du hub.
Autrement dit : le hub reçoit tout via Syncthing, puis une sauvegarde part du hub. Le versioning trashcan vu plus haut est un filet contre les fausses manipulations, pas une politique de sauvegarde.
Dépannage
Section intitulée « Dépannage »Symptômes fréquents et causes réelles, tirés des retours de terrain.
permission denied, fichiers non écrits (Docker) : le volume hôte n'appartient pas à l'UIDPUID. Corrigez avecchown -R 1000:1000sur le volume, pas seulement la variable d'environnement.- Connexion lente ou absente derrière un NAT strict / CGNAT : les nœuds retombent sur des relais publics, avec parfois plusieurs dizaines de minutes avant l'établissement et un débit réduit. Ouvrez le port 22000 (TCP et UDP) en direct quand c'est possible.
- CPU/RAM élevés, sync qui décroche sur gros volumes : relevez la limite
inotifydu noyau (fs.inotify.max_user_watches), placez l'index sur SSD, et espacez les rescans. Syncthing construit une file de tous les fichiers : des centaines de milliers d'entrées coûtent cher. - Migration v1 vers v2 très longue : le passage LevelDB vers SQLite migre la base au premier lancement, ce qui peut durer des heures sur de gros jeux de données. Gardez une sauvegarde avant migration et ne débranchez pas en cours de route. En Docker, épinglez une version majeure pour ne pas basculer par surprise via
latest.
À retenir
Section intitulée « À retenir »- Syncthing v2 est actif et mûr ; il synchronise en P2P chiffré, sans cloud ni compte.
- Un nœud
receiveonlyprotège la source contre une modification faite sur le miroir. - Le versioning trashcan rattrape une suppression accidentelle, mais ne remplace pas une sauvegarde.
- Tout se pilote en CLI (
syncthing cli config ...) et en API REST (X-API-Key), sans toucher la GUI. - En Docker, le piège numéro un est le propriétaire du volume face à
PUID/PGID. - Pour de vraies sauvegardes, combinez Syncthing avec rsync, Rclone ou des snapshots.