Skip to main content

OpenFileSync

·3 mins

An open-source bidirectional file sync tool built on top of rclone bisync. Designed for users who have remote storage (Hetzner Storage Box, any SFTP endpoint) and want Dropbox/Mega-like sync without vendor lock-in.

Why #

Cloud sync services like Mega.nz or Dropbox work great but lock you into their ecosystem. Meanwhile, cheap SFTP storage (like Hetzner Storage Boxes at 3.20 EUR/month for 1TB) has no sync client — just rsync or manual transfers.

OpenFileSync bridges that gap: plug in any SFTP backend and get automatic bidirectional sync between your devices.

Install #

curl -fsSL https://get.openfilesync.runatyr.dev/ | bash

This installs rclone (if missing), inotify-tools, and the ofs binary.

Then run the setup wizard:

ofs init

The wizard will ask you:

  1. SFTP host, port, username, and auth method (password or SSH key)
  2. Which local folders to sync (enter paths one by one, or paste multiple at once)
  3. Confirm a dry-run preview, then run the initial sync
  4. Optionally install a systemd timer for automatic sync every 30 min

Config is saved to ~/.config/openfilesync/. Remote paths mirror your local structure by default (e.g. ~/DocumentsDocuments on the remote).

Features #

  • Bidirectional sync via rclone bisync over SFTP
  • Simple setup — answer 4 questions, syncing in minutes
  • Path mappings — same remote layout, different local paths per device
  • Smart filters — built-in presets for Node.js, Go, Python, Terraform, Ansible, VSCodium, Vim (excludes node_modules, .git, build dirs, caches, etc.)
  • Conflict resolution — newest file wins, losing version saved as .conflict file
  • Self-managed logging — plain log file, auto-trimmed to 15 days
  • Systemd integration — scheduled sync via timer, no cron needed
  • Self-updating — run ofs update to pull the latest version

How It Works #

OpenFileSync wraps rclone bisync with a configuration layer. Each sync mapping defines a local path and its corresponding remote path:

# ~/.config/openfilesync/mappings
# Device A
Documents = /home/user1/important1/Documents
Projects  = /home/user1/important1/projects

# Device B (same remote paths, different local paths)
Documents = /home/user1/Documents
Projects  = /home/user1/projects

On each sync run, the tool iterates over mappings, applies combined ecosystem filters, and runs rclone bisync with safe defaults (--resilient, --recover, --max-delete 10%, --conflict-resolve newer).

Usage #

ofs sync              # Run sync once
ofs sync --dry-run    # Preview changes
ofs sync --force      # Allow bulk deletes (bypass safety limit)
ofs status            # Check sync health
ofs conflicts         # List conflict files
ofs log               # Tail sync log
ofs update            # Update to latest version

Limitations & Behaviors #

  • Full file listing on every sync — rclone bisync lists and compares every file on both sides each run. There is no local change tracking. With large directories (100k+ files) over SFTP, a single sync can take 10-30 minutes even if nothing changed. This is an inherent limitation of rclone bisync. Good filters are critical to keep file counts low.
  • Deletes propagate both ways — deleting a file locally will delete it on the remote (and vice versa). A safety limit aborts if too many files would be deleted in a single run. Use ofs sync --force to override.
  • Empty directories are cleaned up — after each sync, empty directories are removed on both local and remote sides. Filtered paths are excluded from local cleanup (.git, node_modules, .gradle, .cache, .cxx, CMakeFiles, .idea, ios/Pods). Any tool that needs empty dirs should recreate them.
  • Resync merges both sides — when a --resync runs (first sync, filter changes, or error recovery), rclone treats both sides as equally valid and merges them. Files that exist on one side but not the other are copied, not deleted. If you previously synced with another tool, this may restore old files that were intentionally deleted. Delete them again and run a normal sync to propagate.
  • GitHub
  • Install: curl -fsSL https://get.openfilesync.runatyr.dev/ | bash