Deploying Syncthing on Docker: Decentralized P2P File Sync for HomeLab

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

Picture this: it’s 2 AM, your central NAS freezes during a heavy storage scrub, and you urgently need an Ansible playbook or SSH key stored on it. When everything depends on a single hub, one hardware glitch halts your entire workflow. Peer-to-peer (P2P) synchronization solves this issue. By keeping local copies on each active endpoint, your files remain accessible even when your primary server goes dark.

Comparing Centralized Storage, Cloud Drives, and P2P Sync

Before writing compose files, look at how these three storage models handle network splits and host crashes.

Feature Centralized NAS (NFS / SMB / Nextcloud) Proprietary Cloud (Google Drive / Dropbox) Decentralized P2P (Syncthing)
Topology Client-Server (Single Hub) Centralized Third-Party Cloud Decentralized Mesh (Node-to-Node)
LAN Throughput Line-rate (1 Gbps / 10 Gbps) Capped by ISP uplink (often 20–50 Mbps) Line-rate (110+ MB/s over 1GbE, TLS encrypted)
Offline Resilience Zero if the main NAS drops offline Zero without an active internet connection High: Connected LAN devices continue syncing
Data Privacy Self-hosted and fully private Stored on remote corporate infrastructure End-to-end TLS; data stays on your own disks
Memory Footprint Moderate to heavy (500MB–2GB+ for PHP/DB stacks) Negligible on server (proprietary desktop client) Very light (typically 50MB–120MB RAM in Go)

Pros and Cons in a Self-Hosted Environment

Syncthing is a continuous, block-level synchronization engine, not an archival backup utility. Recognizing that distinction helps you place it where it performs best.

Strengths

  • No Storage Paywalls: Sync quotas depend solely on the available disk space across your nodes.
  • Fast Local Discovery: Nodes on the same subnet use IPv4/IPv6 broadcast packets (port 21027/UDP) to link up within seconds, bypassing WAN relays entirely.
  • Block-Level Delta Updates: Changing a few lines inside a 5GB virtual disk image triggers transfers for only the modified 128KB–4MB chunks.
  • Built-In Versioning: Staggered, Trash Can, and Simple versioning policies protect your directories against accidental file overwrites and ransomware.

Trade-offs

  • No Web-Based File Explorer: Syncthing syncs raw files directly to disk. It does not include built-in document editors or media players.
  • Concurrent Node Availability: Data moves directly between peers. At least two devices must be online simultaneously for a transfer to finish, which is why an always-on mini PC or server makes an ideal anchor.
  • Kernel Watch Exhaustion: Tracking large folder hierarchies (like a 40,000-file node_modules directory) can quickly consume default Linux file watcher handles.

Recommended Network and Port Architecture

In a standard homelab setup, run an always-on Syncthing container on a low-power server or NAS. Your laptops, desktops, and mobile devices pair to this node as an always-ready synchronization bridge.

Expose these specific container ports directly to ensure fast LAN discovery and native QUIC protocol performance:

  • 8384/tcp: Web administrative GUI.
  • 22000/tcp & 22000/udp: Core TLS sync traffic and QUIC data transfers.
  • 21027/udp: Local broadcast and multicast discovery.

Step-by-Step Docker Compose Deployment

Step 1: Check Permissions and Create Storage Paths

Identify your user credentials first. Then build dedicated folders for configuration states and synchronized shares:

# Check your active user ID and group ID
id

# Create persistent storage directories
sudo mkdir -p /srv/syncthing/config /srv/syncthing/data
sudo chown -R $USER:$USER /srv/syncthing
chmod -R 755 /srv/syncthing

Step 2: Write the Docker Compose Configuration

Save the following configuration as /srv/syncthing/docker-compose.yml:

services:
  syncthing:
    image: syncthing/syncthing:latest
    container_name: syncthing
    hostname: homelab-syncthing-node01
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Etc/UTC
    volumes:
      - /srv/syncthing/config:/var/syncthing/config
      - /srv/syncthing/data:/var/syncthing/Sync
    ports:
      - "8384:8384"        # Web GUI
      - "22000:22000/tcp"  # TCP sync traffic
      - "22000:22000/udp"  # QUIC sync traffic
      - "21027:21027/udp"  # Local discovery
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-fk", "http://localhost:8384/rest/noauth/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Step 3: Tune Kernel Inotify Limits and Launch

Default Linux inotify caps (often 8,192 watches) cause synchronization lag on large codebases. Raise this limit before spinning up the container:

# Increase inotify user watch allocation to 204,800
echo "fs.inotify.max_user_watches=204800" | sudo tee -a /etc/sysctl.d/90-syncthing.conf
sudo sysctl --system

# Launch Syncthing in detached mode
cd /srv/syncthing
docker compose up -d

# Inspect live startup logs
docker compose logs -f syncthing

Step 4: Initial Hardening and Pairing

  1. Open your browser and visit http://<YOUR_SERVER_IP>:8384.
  2. Go to Actions > Settings > GUI. Enter an admin username, set a strong 16+ character password, and check Use HTTPS for GUI.
  3. Click Actions > Show ID to copy your node’s 56-character cryptographic device fingerprint.
  4. Open Syncthing on your laptop, click Add Remote Device, paste the server ID, and confirm the handshake prompt on both sides.
  5. In the shared folder options, enable Staggered Versioning. This automatically preserves hourly versions for the first day, daily copies for a month, and weekly snapshots thereafter.

Step 5: Quick Troubleshooting Commands

# If peers show 'Relayed' instead of direct LAN connections:
# Ensure firewall rules permit discovery and sync ports
sudo ufw allow 22000/tcp
sudo ufw allow 22000/udp
sudo ufw allow 21027/udp
sudo ufw reload

# If you run into folder sync permission errors:
# Verify host directory ownership matches your PUID/PGID (1000:1000)
ls -ld /srv/syncthing/data
Share: