Lumo Syncthing Kopia Setup for Admins Part 1
Below is a complete, step‑by‑step design you can follow to set up a peer‑to‑peer network with Syncthing (one‑way “send” folders) and then automate backups with Kopia so that, once a device finishes syncing, its data is encrypted and pushed to a cloud storage provider of your choice.
1. Overview of the Architecture
| Component | Role |
|---|---|
| Syncthing | Continuous, encrypted P2P file synchronization. Each device only sends one folder (the “share”) and receives many incoming folders from peers. |
| Introducer | A special device that advertises itself as a device introducer for all other members, allowing new nodes to discover each other automatically without manually adding every device ID. |
| Kopia | Local backup agent that watches the receive folder(s), creates incremental snapshots, encrypts them, and pushes the snapshots to an encrypted cloud repository (e.g., Backblaze B2, Wasabi, S3, Azure Blob, etc.). |
| Trigger script | A small wrapper that runs after Syncthing reports a successful sync, then invokes Kopia to start a backup. |
The flow is:
- Device A starts Syncthing → advertises its send folder.
- All other devices (B, C, …) have that folder listed as a receive folder.
- When the folder’s contents are fully synced, Syncthing fires a “FolderCompletion” event.
- A local watcher script catches that event and calls
kopia snapshot create …. - Kopia encrypts the snapshot and pushes it to the remote cloud repo.
2. Preparing the Environment
2.1 Install Required Software
| OS | Commands (Linux example) |
|---|---|
| Syncthing | curl -s https://syncthing.net/release-key.txt |
| Kopia | curl -LO https://github.com/kopia/kopia/releases/download/v0.13.0/kopia-0.13.0-linux-x64.tar.gz\n tar xf kopia-0.13.0-linux-x64.tar.gz -C /usr/local/bin\n |
| jq (JSON parser, used by the trigger script) | sudo apt install jq |
| inotify-tools (optional, for extra file‑system watching) | sudo apt install inotify-tools |
Tip: All steps work similarly on macOS (Homebrew) and Windows (Chocolatey/Scoop). Adjust package managers accordingly.
2.2 Create a Dedicated System User (optional but recommended)
sudo useradd -m -s /bin/bash syncuser
sudo su - syncuserRunning both Syncthing and Kopia under a non‑root user limits exposure if something goes wrong.
3. Syncthing Configuration
3.1 Global Settings (same on Every node)
-
Open the Syncthing GUI (
http://localhost:8384) → Settings → General- Enable “Introduce Device” – Leave unchecked (we’ll use a dedicated introducer).
- Enable “Global Discovery” – ON (helps new devices find each other).
- Enable “Local Discovery” – ON (LAN broadcast).
- Set “Maximum Concurrent Scans” to a modest number (e.g., 4) to avoid CPU spikes.
-
Certificates – Keep the default self‑signed cert; Syncthing already encrypts traffic end‑to‑end.
3.2 Designate an “Introducer” Device
Pick one machine (often a server or a device that is always online) to act as the introducer.
On that device:
- In Settings → Advanced → Device, edit the device entry (or add a new one) and tick “Introducer”.
- Give it a clear name, e.g.,
INTRODUCER. - Copy its Device ID (visible at the top of the GUI). You’ll need it for the rest of the flet.
3.3 Adding Devices via the Introducer
For every other node (A, B, C …):
- Add the introducer’s Device ID manually (Settings → Devices → Add Device).
- After the introducer appears in the list, check the box “Introduced By” next to the introducer’s entry. This tells Syncthing: “Treat any device that the introducer knows about as a trusted peer.”
Once the introducer knows about a device, it will automatically push that device’s ID to all other peers that have the introducer marked. No further manual entry is required.
3.4 Folder Setup – One‑Way Send Only
Assume each device has a single folder called SharedOut that it wants to push to everyone else.
On Each Device (example for Device A)
-
Create the folder locally (e.g.,
/home/syncuser/shared_out). -
In the Syncthing UI → Folders → Add Folder
- Folder ID:
shared-out-A(must be unique across the whole cluster). - Folder Path:
/home/syncuser/shared_out - Folder Type: Send Only (this disables any inbound changes).
- Ignore Patterns: Add any temporary files you don’t want to propagate (
*.tmp,.DS_Store, etc.).
- Folder ID:
-
Share the folder with all other devices (checkboxes under “Sharing”). Because we rely on the introducer, you can simply select “Share with all devices” – Syncthing will propagate the sharing info automatically.
On Every other Device (B, C, …)
- The same folder will appear under “Remote Devices”. Click “Add” to accept it as a Receive Only folder.
- Choose a local path where you want the incoming data stored, e.g.,
/home/syncuser/incoming/from-A. - Do NOT change the folder type – keep it Receive Only.
Repeat the above for each device’s own send‑only folder (shared-out-B, shared-out-C, …). The result is a star‑topology where every node pushes its own data outward, while receiving from all peers.
3.5 Fine‑Tuning Synchronisation Behaviour
| Setting | Recommended Value | Why |
|---|---|---|
| Folder Rescan Interval | 60s (default) | Keeps detection responsive without hammering the disk. |
| Sync Pull Order | Random (default) | Prevents a single node from becoming a bottleneck. |
| Max Concurrent Transfers | 2 (per folder) | Limits bandwidth spikes on slower links. |
| Versioning | Simple Versioning with keep = 5 (optional) | Provides a short‑term safety net if a file is accidentally overwritten before the backup runs. |
| Auto‑Upgrade | Off (manage upgrades centrally) | Guarantees all nodes stay on the same version, avoiding protocol mismatches. |
4. Kopia – Encrypted Cloud Backup
4.1 Initialise a Repository
Pick a cloud provider that supports S3‑compatible APIs (Backblaze B2, Wasabi, DigitalOcean Spaces, etc.) or a native provider (Azure, GCS). Example using Backblaze B2:
export B2_ACCOUNT_ID=your_account_id
export B2_APPLICATION_KEY=your_app_key
export B2_BUCKET=my-kopia-backups
kopia repository create b2 \
--bucket=$B2_BUCKET \
--account-id=$B2_ACCOUNT_ID \
--account-key=$B2_APPLICATION_KEY \
--password=YOUR_STRONG_PASSWORD \
--encryption=AES256-GCMSecurity note: Store the password in a password manager or a secure environment variable; never hard‑code it in scripts.
4.2 Define a Snapshot Policy
Create a policy that keeps daily snapshots for 30 days, then weekly for 12 weeks, and finally monthly for a year.
kopia policy set \
--global \
--keep-daily 30 \
--keep-weekly 12 \
--keep-monthly 12 \
--compression=auto \
--snapshot-ttl=365d4.3 Backup Script (run after Each Folder sync)
Create a script ~/sync-to-backup.sh:
#!/usr/bin/env bash
set -euo pipefail
# -------------------------------------------------
# Arguments
# -------------------------------------------------
FOLDER_PATH="$1" # Full path of the *receive* folder that just finished syncing
DEVICE_NAME="${2:-$(hostname)}"
# -------------------------------------------------
# Logging helper
# ----------------------------------------------
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') [$DEVICE_NAME] $*"
}
log "Starting Kopia backup for ${FOLDER_PATH}"
# -------------------------------------------------
# Create a snapshot (Kopia automatically encrypts)
# -------------------------------------------------
kopia snapshot create "${FOLDER_PATH}" \
--description="Syncthing sync from ${DEVICE_NAME} $(basename "${FOLDER_PATH}")" \
--tags="syncthing,auto"
log "Snapshot created successfully"
# -------------------------------------------------
# Optional: Force immediate upload (normally Kopia uploads in background)
# -------------------------------------------------
kopia maintenance run --full
log "Backup job finished"Make it executable:
chmod +x ~/sync-to-backup.sh4.4 Systemd Service (Linux) – Keep the Script Ready
# /etc/systemd/system/kopia-sync.service
[Unit]
Description=Kopia backup triggered by Syncthing folder completion
After=network-online.target
[Service]
Type=oneshot
ExecStart=/home/syncuser/sync-to-backup.sh %i %h
User=syncuser
Environment=PATH=/usr/local/bin:/usr/bin:/binYou’ll invoke this service later via the Syncthing event listener.
5. Wiring Syncthing → Kopia (Event‑Driven Trigger)
Syncthing can emit events over a local HTTP API. We’ll use a tiny watcher written in Bash/Python (both work; Bash is enough for most Linux boxes).
5.1 Enable the Event API
In Syncthing UI → Settings → Advanced → GUI Authentication
- Set API Key (or leave blank for no auth on localhost).
- Ensure “Enable HTTPS” is ON (default).
Take note of the API key; you’ll need it for the script.
5.2 Event Listener Script (~/syncthing-watcher.sh)
#!/usr/bin/env bash
set -euo pipefail
API_KEY="YOUR_SYNCTHING_API_KEY" # replace with the key from the GUI
API_URL="http://127.0.0.1:8384/rest/events"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') [Watcher] $*"
}
log "Connecting to Syncthing event stream..."
# Long‑running curl that yields newline‑delimited JSON events
curl -s -H "X-API-Key: $API_KEY" "$API_URL?events=FolderCompletion" |
while read -r line; do
# Guard against empty lines
[[ -z "$line" ]] && continue
# Extract folder ID and device ID using jq
folder_id=$(echo "$line" | jq -r '.data.folder')
device_id=$(echo "$line" | jq -r '.data.device')
log "Folder $folder_id completed sync from device $device_id"
# Map folder IDs to the local receive‑folder paths.
# Adjust this associative array to match your naming convention.
declare -A FOLDER_MAP=(
["shared-out-A"]="/home/syncuser/incoming/from-A"
["shared-out-B"]="/home/syncuser/incoming/from-B"
["shared-out-C"]="/home/syncuser/incoming/from-C"
)
recv_path="${FOLDER_MAP[$folder_id]:-}"
if [[ -z "$recv_path" ]]; then
log "No receive path configured for $folder_id – skipping."
continue
fi
# Trigger Kopia backup via systemd (asynchronous, fire‑and‑forget)
systemctl start kopia-sync@${recv_path}.service
done- Save the file, make it executable (
chmod +x ~/syncthing-watcher.sh). - Replace
YOUR_SYNCTHING_API_KEYwith the actual key. - Update the
FOLDER_MAPassociative array to reflect the exact folder IDs you defined in Syncthing.
5.3 Run the Watcher as a Service
Create a systemd unit:
# /etc/systemd/system/syncthing-watcher.service
[Unit]
Description=Syncthing FolderCompletion event watcher
After=syncthing.service
Wants=syncthing.service
[Service]
Type=simple
User=syncuser
ExecStart=/home/syncuser/syncthing-watcher.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl enable --now syncthing-watcher.serviceNow, whenever Syncthing finishes syncing a receive folder, the watcher fires the corresponding kopia-sync@<path>.service, which runs the backup script for that folder.
6. End‑to‑End Test Procedure
-
Start all services on every node:
systemctl restart syncthing.service systemctl restart syncthing-watcher.service -
Place a test file in Device A’s
shared_outdirectory. -
Verify on Device B/C that the file appears in their respective
incoming/from-Adirectories. -
Wait ~10 seconds (the event propagation delay).
-
Check the Kopia logs on Device B:
journalctl -u kopia-sync@/home/syncuser/incoming/from-A.service -fYou should see “Starting Kopia backup…”, snapshot creation, and eventual “Backup job finished”.
-
Log into your cloud console (e.g., Backblaze B2 bucket) and confirm a new snapshot file (named like
snapshot-xxxx.kopia) appears.
Repeat the test for each device’s folder to ensure the whole mesh works.
7. Optional Enhancements
| Goal | How |
|---|---|
| Bandwidth throttling per peer | In Syncthing UI → Folder → Advanced → Rate Limit – set a per‑folder limit (e.g., 500KB/s). |
| Automatic device onboarding | Write a tiny script that, on first boot, contacts the introducer via its REST API (/rest/system/config) to fetch the latest device list and adds missing IDs. |
| Retention policy for old snapshots | Use kopia policy set --keep-last 5 on a per‑folder basis if you need tighter control. |
| Alerting | Hook the watcher script into a monitoring system (Prometheus node exporter, Grafana alerts) by emitting metrics (curl -X POST http://prom-pushgateway/...). |
| Multi‑cloud redundancy | Create two repositories (e.g., B2 + Wasabi) and run kopia snapshot push to both after each snapshot. |
8. Security Checklist
- Syncthing: All traffic is TLS‑encrypted; verify each device’s certificate fingerprint in the UI.
- Kopia: Uses client‑side AES‑256‑GCM encryption; the encryption key never leaves the host.
- API Keys: Store the Syncthing API key in a file readable only by
syncuser(chmod 600). - Systemd Services: Run under the non‑privileged
syncuseraccount; limitCapabilityBoundingSet=if you want extra confinement. - Cloud Credentials: Use short‑lived application keys (Backblaze allows per‑bucket keys) and rotate them regularly.
9. Quick Reference Cheat‑Sheet
| Action | Command |
|---|---|
| Start Syncthing | systemctl start syncthing.service |
| Force a folder rescan | curl -X POST -H "X-API-Key: $API_KEY" http://127.0.0.1:8384/rest/db/scan?folder=shared-out-A |
| Manually trigger a backup | ~/sync-to-backup.sh /home/syncuser/incoming/from-A $(hostname) |
| View Kopia snapshots | kopia snapshot list /home/syncuser/incoming/from-A |
| Check watcher logs | journalctl -u syncthing-watcher.service -f |
| Rotate cloud credentials | Update env vars and run kopia repository connect .. again. |
🎉 You’re now Ready
With the introducer‑based mesh, each device only needs to know a single “introducer” device, yet all folders propagate automatically. The event‑driven Kopia integration guarantees that as soon as a folder is fully synchronized, an encrypted, versioned backup lands safely in your chosen cloud storage—without any manual intervention.
Feel free to adapt the folder‑ID ↔ path mapping, tweak retention policies, or swap in a different cloud backend; the core pattern stays the same. Happy syncing and backing up!
Backlinks
Lumo Checking for Pegasus malware and analyzing silent SMS attack vectors
Lumo Syncthing Kopia Setup for Admins Part 1
Lumo Syncthing Kopia Setup for Admins Part 2 - Building a syncnet with SyncThing
Lumo Orbic hotspot Rayhunter setup
Notesnook Github Vercel project private wiki