Syncthing
Syncthing 2.1.2 on docker-main as an always-on peer for my Obsidian vault, from 2026-07-22 to 2026-08-06. The capability drop that stopped it starting, the sync alternatives I weighed, and the decommission.
For two weeks Syncthing kept a second, always-on copy of my Obsidian vault on docker-main, with 90 days of file versions. My Windows PC held the working copy, because Obsidian works from local files, and the two synchronized directly. On 2026-08-06 I decided I didn’t want the service any more and decommissioned it.
| Item | Value |
|---|---|
| Version | Syncthing 2.1.2 on both peers, pinned rather than following a floating tag |
| Server peer | docker-main, container syncthing, with host networking for LAN discovery |
| Desktop peer | My Windows PC, installed from WinGet and started at login |
| Folder | obsidian-the-vault, send and receive on both peers |
| Versioning | Staggered, 90 days, on the server only |
| Excluded files | .obsidian/workspace.json and .obsidian/workspace-mobile.json |
| Interface | An internal HTTPS name through Nginx Proxy Manager; only the proxy could reach its port |
| Deployed | 2026-07-22 |
| Retired | 2026-08-06 |
What it synced
The vault was small: 15 files in six directories, about 6.4 MB, including the .obsidian folder with the Minimal theme and the Kanban and Excalidraw plugins. By the decommission it had grown to 17 files and 9.4 MB, with two archived versions.
I excluded the two workspace files because they hold each device’s interface state and change constantly. Plugins, themes, hotkeys and the rest of .obsidian stayed in sync. Before pairing anything I zipped the vault as a recovery point for its original state.
The peers connected directly across VLANs, from my workstation’s network to docker-main’s, over TLS 1.3, so the firewall needed no change for synchronization. I checked the result with a canonical SHA-256 manifest generated independently on both peers, which matched over the 14 synchronized files. Then I tested the round trip: a small file created on the server arrived on Windows with the same hash, and when I deleted it on Windows, the server removed its live copy and archived the same hash in its version folder.
The capability-drop restart
The first container never started Syncthing at all. I had deployed it with cap_drop: ALL, and it went into a restart loop, reaching restart count 7 and unhealthy without opening any of its listeners. The logs showed why:
chown: /var/syncthing: Operation not permitted
su-exec: setgroups(1000): Operation not permitted
The image’s entrypoint changes ownership of its data directory and then switches to UID and GID 1000, and both steps need capabilities I had dropped. I removed only cap_drop: ALL, kept no-new-privileges:true, and recreated the container from the same image. It came up healthy with a restart count of 0. Because Syncthing never started during the loop, the failed container never scanned or touched the vault.
Obsidian sync alternatives
On 2026-07-27 I wrote up the free and self-hosted alternatives for one ordinary Obsidian vault across computers and phones. The conclusion was to keep Syncthing unless an iPhone or iPad became a normal part of how I edit notes.
The point that settled most of it: installing something on every device isn’t a weakness of Syncthing. Every method needs code on each device to notice a changed file, send it, receive other changes and write them into the local vault. Another product can hide that inside Obsidian, but it can’t remove it.
| Option | Conflicts | History | Mobile | Verdict |
|---|---|---|---|---|
| Syncthing | Keeps a separate conflict file; I merge by hand | Server versions for 90 days | Community clients on Android and iOS | Best fit, already deployed |
| Self-hosted LiveSync and CouchDB | Merges simple conflicts and asks about harder ones | Database revisions, which compaction discards | Runs inside Obsidian everywhere | The best alternative if mobile matters |
| Remotely Save with WebDAV or S3 | Detects a conflict and asks which copy to keep; merging is paid | Depends on the storage behind it | Runs inside Obsidian on Android and iOS | A simpler mobile option |
| Nextcloud desktop sync | Keeps a local conflicted copy | Built-in server versions | Mobile apps give file access, not necessarily a local vault | Only if I wanted a general private cloud anyway |
| Git | Three-way merges, otherwise manual | The best history | The Obsidian Git plugin calls mobile support unstable | Better as a history layer than as the sync |
| Seafile | Keeps a separate conflict file | Server version control | Mobile apps give file access | No advantage over Syncthing here |
Syncthing also kept working when Obsidian was closed, which the plugin-based options can’t: they synchronize only while Obsidian runs, and mobile systems can suspend it in the background.
I set two conditions for reconsidering. If iPhone or iPad editing became normal, I would test Self-hosted LiveSync with CouchDB against a copy of the vault. If I deployed Nextcloud for general file storage anyway, I would test Remotely Save against its WebDAV endpoint, but I wouldn’t deploy Nextcloud for this vault alone. Either way, I wouldn’t run two sync engines against the live vault; LiveSync’s own documentation warns against it, so any trial starts with a separate copy.
Decommission, 2026-08-06
Ten days later I retired it anyway. Syncthing existed so the vault had an always-on second copy and 90 days of versions, and I decided I didn’t want the service any more. I chose to delete the server copy and its version history along with the service, deliberately rather than as an oversight. The vault on my Windows PC was untouched, and Obsidian carried on working from it.
- Service and data.
docker compose down --rmi allremoved the container and its image in one pass. Then I deleted the Compose directory with its configuration and the data directory with the vault copy and versions. Afterwardsdocker-mainhad no matching container, image, volume, directory or systemd unit, and nothing listened on Syncthing’s ports. - Monitoring. I removed the Prometheus probe for its HTTPS name and checked the config with
promtool. The reload didn’t take, twice. The lifecycle API is disabled, soPOST /-/reloadreturned 403, and theSIGHUPI sent instead changed nothing either:prometheus.ymlis a single-file bind mount, andsed -iwrites a replacement file rather than editing in place, so the container kept reading the old inode. Recreating the container picked up the new file, and Prometheus ended at 48 of 48 targets up. - Network. I deleted the proxy host through Nginx Proxy Manager’s API and the internal DNS record from UniFi.
- Records. The platform folder moved to
Archive/with its Compose file, deployment record, device runbook, the alternatives write-up and the deployment evidence. Its open items, such as pairing a laptop, closed with it.
Note: A
sed -iagainst a single-file bind mount needs a container recreate, not a reload. The same trap had caught me on this Prometheus host on 2026-07-13 and again during the Kasm work on 2026-07-28.
The same day I closed the two follow-ups. A shared UniFi policy let the proxy reach several web interfaces on docker-main. I checked every port in it against the live listeners and removed the two with nothing behind them, Syncthing’s and the one left by Termix, retired on 2026-07-28. The five remaining services still answered through the proxy and their probes stayed green. I archived the stored Syncthing credential rather than destroying it.