dps — Debian Profile Sync
Keep your shell config, dotfiles, and editor settings identical across every Debian machine you own — automatically, in real time, over any network.
dps spins up a lightweight Proxmox LXC container that acts as the central sync hub. Every machine runs the dps-daemon in the background; it watches for local file changes and pushes them to the container, and periodically pulls changes made from other machines. A system-tray GUI (dps-gui) gives you live status at a glance.
Features
- One-command setup — interactive wizard creates the LXC container, injects your SSH key, and optionally joins Tailscale
- Real-time push — inotify watcher debounces changes and rsyncs instantly
- Periodic pull — background poller keeps you in sync when you return to a machine
- Tailscale integration — sync works from any network without opening firewall ports
- Machine-specific file filtering — built-in patterns skip hostname files, dconf, pulse TDB, recently-used lists, etc.
.syncignoresupport — per-directory exclusion rules (gitignore syntax)- System-tray GUI — egui app connects to the daemon over a Unix socket
- systemd user service — daemon starts at login, restarts on failure
Requirements
| Requirement | Notes |
|---|---|
| Proxmox VE 7+ | Any node with LXC support |
| Debian/Ubuntu client machines | rsync and ssh must be in PATH |
| Rust 1.75+ | Only needed to build from source |
| GTK3 + libayatana-appindicator3 | Only for the GUI binary |
Install GUI system deps on Debian/Ubuntu:
Installation
From crates.io (CLI + daemon only)
From source (all binaries including GUI)
Quick Start
# 1. Run the interactive setup wizard — creates config + provisions the container
# 2. Enable the background daemon
# 3. On every other machine: install dps, copy your config, enable the daemon
# (no `dps setup` needed — the container already exists)
# 4. Manual sync
# 5. Or watch continuously
Setup Wizard
Running dps setup with no config file launches a step-by-step wizard:
╔══════════════════════════════════════╗
║ dps — first-time setup ║
╚══════════════════════════════════════╝
── Proxmox Connection ───────────────────────────────────────────────
Host (IP or hostname): 192.168.1.10
Port [8006]:
Node name [pve]:
Verify SSL certificate [y/N]:
── Authentication ────────────────────────────────────────────────────
Type (token/password) [token]:
User [root@pam]:
Token name [dps]:
Token value: ****
── LXC Container ─────────────────────────────────────────────────────
VMID [200]:
Hostname [dps-sync]:
...
── Profile Sync ──────────────────────────────────────────────────────
Local path [1/?]: ~/.bashrc
Remote path [.bashrc]:
...
── Tailscale (optional) ──────────────────────────────────────────────
Enable Tailscale integration [y/N]:
The wizard saves ~/.config/dps/config.toml and immediately provisions the container.
CLI Reference
dps setup First-time setup (wizard + container provisioning)
dps push [--dry-run] Push local files → container
dps pull [--dry-run] Pull container → local files
dps check Report machine-specific files that would be skipped
dps watch Real-time push watcher + periodic pull poller
dps status Show container and sync status
dps start Start the LXC container
dps stop Stop the LXC container
dps destroy Destroy the LXC container (requires --yes)
dps tailscale status Show Tailscale status inside the container
dps tailscale reauth <key> Re-authenticate Tailscale with a new auth key
Configuration
Config lives at ~/.config/dps/config.toml. A full annotated example is at config.example.toml.
Minimal example (API token auth)
[]
= "192.168.1.10"
= "pve"
[]
= "token"
= "root@pam"
= "dps"
= "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
[]
= 200
= "dps-sync"
= "local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst"
= "local-lvm"
= "8G"
= "change-me"
[]
= "vmbr0"
= "dhcp"
[]
[[]]
= "~/.bashrc"
= ".bashrc"
[[]]
= "~/.gitconfig"
= ".gitconfig"
Tailscale
[]
= "tskey-auth-..."
= true
When prefer_tailscale_ip = true, all push/pull transfers use the Tailscale IP (stored automatically after dps setup), so sync works from any network.
Daemon
[]
= true
= true
= "both" # "push", "pull", or "both"
= 500
= 30
Background Daemon
The daemon maintains the watcher processes and exposes a Unix socket at $XDG_RUNTIME_DIR/dps.sock for the CLI and GUI to connect to.
# Install and enable
# Logs
System-Tray GUI
Build and install (requires GTK3 + libayatana-appindicator3):
The tray icon turns green when connected to the daemon. Left-click toggles the control window; right-click shows the menu.
Ignoring Files
.syncignore
Create a .syncignore file inside any synced directory to exclude files from that directory (gitignore syntax):
*.log
.env
secrets/
Global ignore
Add patterns to ~/.config/dps/syncignore to exclude files across all paths.
Built-in machine-specific patterns
dps automatically skips files that contain your hostname or machine-id, plus a built-in list of known machine-specific paths:
.cache/
monitors.xml
recently-used.xbel
pulse/*.tdb
tracker/
dconf/
Run dps check to see which files in your sync paths would be flagged.
License
MIT