Skip to content
Infrastructure

Self-hosting file sync with Syncthing, kept local-only

By Victor Da Luz
homelab syncthing proxmox docker self-hosted privacy

I wanted to keep a handful of folders in sync across my machines, the way Dropbox or iCloud Drive does, without putting the files on anyone else’s servers. Syncthing does exactly that: continuous, encrypted, peer-to-peer sync between your own devices, with no central account. The part I cared about most was running it entirely on my own network: no global discovery, no relay servers, nothing announcing my devices to the internet.

Why local-only

By default Syncthing is built to connect your devices from anywhere. It uses global discovery servers, run by the Syncthing project, so two devices can find each other across the internet, and relay servers to pass traffic when they cannot reach each other directly. That is genuinely useful if your laptop syncs from a coffee shop. But every device I sync is on my own network, so I need neither, and I would rather not announce my device IDs to public discovery servers at all. The goal was local-only: keep local discovery, turn global discovery and relaying off.

The deploy: Docker-in-LXC with host networking

Same pattern as the rest of the homelab, a Docker Compose stack in a Proxmox LXC container, driven by Ansible. Syncthing is light: I gave the container a single core and 1GB of RAM, a fraction of what a photo or database service wants.

One compose setting matters more than the rest:

syncthing:
  image: lscr.io/linuxserver/syncthing:latest
  network_mode: host

Host networking, not a bridged Docker network. Syncthing finds peers on the LAN using broadcast and multicast, and that traffic does not cross Docker’s bridge. On a bridge network the web UI works fine while local discovery quietly fails, and once you have turned off global discovery, local discovery is the only kind you have left. Host networking is what keeps it working.

Going local-only

Out of the box Syncthing has three discovery mechanisms. The local-only setup keeps one and drops two:

  • Local discovery (broadcast and multicast on the LAN): keep it. This is how devices on the same network find each other.
  • Global discovery (the public discovery servers): turn it off.
  • Relaying (the public relay servers): turn it off.

In the web UI that is two checkboxes under settings: uncheck Enable Global Discovery and uncheck Enable Relaying. The check I actually trust, though, is the listen addresses. After disabling both, a device’s listen addresses should show only local entries like tcp://0.0.0.0:22000, with no global+https://discovery.syncthing.net or dynamic+https://relays.syncthing.net endpoints. If those public endpoints are still listed, something is still reaching out.

Static addresses: the cost of turning discovery off

Turning global discovery off has a consequence worth knowing before you do it. With it on, a device finds its peers anywhere with no addressing at all. With it off, devices rely entirely on local discovery, and if that fails for some reason, a multicast-filtering switch or a VLAN boundary, a peer just shows as disconnected with no obvious cause.

The fix is to stop relying on discovery for those peers and point them at each other directly. In each device’s settings you add the other device’s static address, its LAN IP and Syncthing’s sync port:

tcp://192.168.x.x:22000

It is more manual than the auto-everything default, but it is deterministic and it never leaves the network. Devices that move around can stay on dynamic and lean on local discovery; the always-on ones get a static address and connect reliably every time.

Storage and the web UI

The synced data lives on my QNAP NAS over an SMB mount, so the files Syncthing manages sit on redundant storage and are backed up with everything else, rather than only existing on the container’s disk. The web UI runs on port 8384 and sits behind Traefik over HTTPS like every other service.

Lessons

  • If every device is on your own network, run Syncthing local-only. Keep local discovery, disable global discovery and relaying, and nothing about your sync touches the internet.
  • Use host networking in Docker. Syncthing’s local discovery is broadcast and multicast, which does not cross a bridge network. On a bridge the UI works and discovery silently does not.
  • Trust the listen addresses, not the checkboxes. After disabling global discovery and relaying, confirm the device lists only local listen addresses and no public discovery or relay endpoints.
  • Disabling discovery means you own the addressing. Set static LAN addresses for the peers that matter, so a flaky multicast path does not look like a broken sync.
  • It is a tiny service. One core and a gigabyte of RAM is plenty; the interesting part is the network configuration, not the resources.

Related reading

Infrastructure

Researching update automation for the homelab

Twenty-three self-hosted services and no update process beyond "when I remember". I compared Watchtower, Diun, Renovate, and WUD, looked at unattended-upgrades for system packages, and landed on a hybrid plan.

Read
Infrastructure

Deploying RomM, a self-hosted ROM manager, in the homelab

I wanted a web-based, self-hosted way to organize a pile of game backups with real metadata. RomM was the only option that fit. Here is the Docker-in-LXC deployment, the two gotchas that cost me time, and the NAS mount mistake that bit me later.

Read
Infrastructure

Adding AI object detection to my cameras with Frigate

My NVR recorded everything and understood nothing. Frigate adds real-time object detection on top of the cameras I already had. Here is the deploy, including the first attempt I had to shelve, and the Intel iGPU that made it usable.

Read

Ready to Transform Your Career?

Let's work together to unlock your potential and achieve your professional goals.