⇄ shuttle
⇄

Push, pull and sync folders between your Linux or Windows desktop and a NAS, over SMB or NFS, with no mounts and no root. Set it up in the terminal; a user service runs it; GNOME, or the icon by Windows' clock, shows what it is doing. And the same on your Android phone, in an app.

↑ push   ↓ pull   ⇅ sync  ·  real time, on a schedule, when the share comes online, or when you ask

The problem

Every tool does part of the job

Keeping folders on a Linux desktop in step with folders on a NAS or file server means picking between tools that each leave something out.

rsync
✗ one-way, no memory

It has no idea what happened since the last run, so it cannot tell a file you deleted from one that is new on the other side. A safe two-way sync is out of reach.

Syncthing
✗ needs a peer on the NAS

It syncs both ways well, but only with another Syncthing on the other side. An SMB or NFS share is not one.

mount + a script
✗ fstab, root, a mount that may be gone

The job is tied to an fstab entry, root, and a mount that is not there when you are away from home or the VPN is down.

all of them
✗ invisible on the desktop

None shows what it is doing in GNOME, or lets you pause from Quick Settings when you are on a slow connection.

The mission

One tool for all of it, as simple as an email client

Each folder pair is a shuttle: it pushes, pulls or syncs both ways against a share it connects to directly. You describe it once, in a terminal interface or a plain config file, and it keeps going: in real time, on a schedule, or whenever the share is back. When something needs you, a conflict or a share gone missing, it says so, on the desktop, and waits.

Nothing is lost on the way: every write lands whole or not at all, a scan that failed never turns into deletions, and what a sync replaces is kept.

What sets it apart

Built for a NAS, not for the cloud

No mounts, no root

shuttle speaks SMB 2/3 and NFSv3 itself, as you, from a user service. No fstab entry, no sudo, no mount to keep alive. An already-mounted path works too, for NFSv4.

Two-way sync that remembers

A record of every file's last synced state tells "deleted here" from "new there", and a change on both sides becomes a conflict, settled your way: keep both, newest wins, or ask.

Made not to lose files

Writes go to a temp name and are renamed into place. A failed or partial scan never deletes; a run that would delete too much at once is held for you. Replaced files can be versioned, and a run that would not fit stops before it copies.

At home on GNOME

A top-bar indicator with the live transfer rate, a Quick Settings toggle to pause everything or one shuttle, and notifications that open the terminal interface right where something waits for you.

Main features

Everything a folder pair needs

↑ ↓ ⇅

Push, pull or sync

One way to the share, one way from it, or both. Push and pull mirror deletions, or add only.

⠹

Runs when it should

Real time as files settle, on an interval or at set times, when the share comes back online, or only when you ask. Combine them.

▤

Profiles

Reusable settings, "Live sync" or "Nightly backup", that a shuttle overrides one setting at a time.

⚑

Conflicts your way

Keep both, newest wins, or hold the file until you choose, with both copies' size and time side by side.

⟲

Versioning

Keep replaced files for N days, the last N versions, or on a staggered schedule, with a size cap.

☑

Selective sync

Mark files and folders on a tree of the share or of this computer; or ignore by gitignore-style patterns.

⇣

Bandwidth limits

Up and down, per shuttle, and a global cap across all of them that applies from the next file.

▦

Room checked first

Free space on both sides is shown, and a run that would not fit stops before it copies, saying how much it needed.

⚿

Passwords in the keyring

Share passwords live in GNOME Keyring or Windows' Credential Manager, never in the config file, logs or process arguments.

✎

A config that follows you

Edit config.toml by hand or in the interface, comments kept: changes apply within a second, no restart.

☰

Activity log

Every copy, deletion, conflict and error, newest first, kept for 30 days, per shuttle or all together.

❯_

A command line too

shuttle status, sync, pause, resume and activity, for scripts and quick checks.

▯

On your phone

An Android app, from Android 11: the same engine and every setting, set up in its own tabs, real time in the background, and backups of its setup. A signed APK in each release.

The terminal interface

Every shuttle live, in one screen

Progress, transfer rates and whether each share is online; under them, the selected shuttle in full, its rate drawn as it goes. Tabs for conflicts, the activity log, profiles and shares. ? lists the keys.

  shuttle
shuttle's dashboard: five shuttles, two of them pushing to a NAS; below, the selected one in full, with its transfer rate as a sparkline

The real interface, drawn from a run against a test daemon.

How it works

A service that runs as you, and what talks to it

One binary: the terminal interface, the service and the command line. The service does the syncing; everything else asks it over the session bus.

Terminal interfaceshuttle
GNOME extensiontop bar · Quick Settings
Command lineshuttle status, sync…
⇄D-Bus
session bus
shuttle daemona systemd user service: triggers, scans, sync, conflicts, versions, notifications

config.toml · state · GNOME Keyring
⇄direct,
as you
SMB 2/3Samba, Windows, Synology, QNAP, TrueNAS
NFSv3its own client: no kernel mount
A mounted pathNFSv4, or anything already mounted

Install

Fedora, Debian and Ubuntu, on GNOME 50, Windows 11, and Android

From the latest release, as a package (amd64; arm64 built, not yet tested), then enable the service:

$ v=0.3.0
$ url=https://github.com/fqazzazee/shuttle/releases/download/v$v

# Fedora
$ sudo dnf install $url/shuttle_${v}_linux_amd64.rpm

# Debian, Ubuntu
$ curl -LO $url/shuttle_${v}_linux_amd64.deb
$ sudo apt install ./shuttle_${v}_linux_amd64.deb

# then, for you
$ systemctl --user enable --now shuttle
$ shuttle

Then a share, a profile and a shuttle: in the interface's tabs, or by hand

# ~/.config/shuttle/config.toml
[shares.nas]
type = "smb"
host = "nas.example"
share = "home"
user = "you"        # the password: in the keyring

[profiles.live]
mode = "sync"
triggers = ["realtime", "share-available"]

[shuttles.documents]
profile = "live"
local = "~/Documents"
remote = "nas:/docs"

The README has the rest: building from source, NFS exports, the GNOME extension, every setting.

On an Android phone (Android 11 or later, arm64): download shuttle_0.3.0_android_arm64.apk on the phone and open it. The app sets up shares, profiles and shuttles in its own tabs, and each release installs over the last, keeping them. Every release is signed with the same key: its About page shows the APK's SHA-256, to compare with the release's checksums.txt. See the README.

On Windows 11 (amd64; arm64 built, not yet tested): unzip shuttle_0.3.0_windows_amd64.zip into a folder of its own and run shuttle autostart on there: the service and an icon in the notification area then start when you sign in, and shuttle opens the same terminal interface. The programs are not code-signed, so Windows warns once; each release's files carry GitHub's build attestations. See the README.

shuttle is not:

a cloud sync clienta backup tool with deduplicationpeer-to-peer, like Syncthing

FAQ

Questions people ask

How is it different from Syncthing?

Syncthing syncs between machines that each run Syncthing. A NAS share is not one of them. shuttle talks to the share itself, over SMB or NFS, so there is nothing to install on the NAS. For syncing machines with each other, without a share in between, Syncthing is the right tool.

Do I need to mount the share, or be root?

No. shuttle speaks SMB 2/3 and NFSv3 itself, from a service that runs as you: no fstab entry, no sudo, no mount. A share that is already mounted works too, as a folder path.

My NAS speaks NFS: what does it need?

Running as you, shuttle connects from a port above 1024. Linux servers refuse that unless the export has insecure in /etc/exports; on a Synology, tick "Allow connections from non-privileged ports". A server that speaks only NFSv4: mount it as usual and add the mount point as a share of type path.

Which file servers does it work with?

Anything that serves SMB 2/3 or NFSv3: Samba, Windows, Synology, QNAP, TrueNAS. Its tests run against a real Samba server, the Linux kernel's NFS server, and an in-process NFS server.

Both folders already have files. What does the first sync do?

It joins them: what is on one side only is copied to the other. Files that exist on both sides but differ become conflicts, settled by the shuttle's conflict setting. Nothing is overwritten silently.

What if a file changes on both sides?

That is a conflict, settled your way. Keep both saves the older copy beside the newer one under a conflict name. Newest wins keeps the latest, and versions the other if versioning is on. Ask holds the file until you choose in the Conflicts tab, with both copies' size and time.

Can it delete my files by accident?

It is built not to. A scan that fails or stops partway never turns into deletions. If a run would delete more than half of a shuttle's files at once (and at least 10), it holds those deletions until you allow them; that threshold is a setting, and can be turned off. Push and pull can be set to add only, never delete. And versioning keeps what a sync replaces or deletes.

What if the NAS goes offline, or I am away from home?

Every share is checked every 30 seconds, and the dashboard and the top bar show it offline. A run that loses the share stops, with nothing half-written: files are written to a temporary name and renamed into place. With the share available trigger, the shuttle runs again as soon as the share is back.

Where are my passwords kept?

In the Secret Service: GNOME Keyring on a GNOME desktop. Never in the config file, the logs, D-Bus replies or process arguments.

Do I need GNOME?

Only for the top-bar indicator and the Quick Settings toggle, which need GNOME Shell 50. The service, the terminal interface and the command line run on any Linux desktop with systemd and a Secret Service.

Can I edit the config by hand?

Yes: it is ~/.config/shuttle/config.toml. Save a change and it applies within a second, with no restart. A mistake keeps the previous settings running, and says what is wrong. The terminal interface edits the same file, keeping your comments and layout.

Is there a phone app?

Yes, for Android 11 and later: the same engine, settings and config file as the desktop, with a wizard to add a shuttle, conflicts, activity, and backups of its setup. It is a signed APK on the releases page, not on Google Play or F-Droid; Obtainium can follow the releases.

Does it run on macOS or Windows, or sync to the cloud?

No: it runs on Linux and Android, and it syncs with SMB and NFS shares. For cloud storage (S3, Google Drive, OneDrive), use rclone.

Is it free?

For personal, hobby and home-lab use, for charities, schools, public research and government, and for a company using it for its own internal operations: yes, under the PolyForm licenses. Using it to do work for someone else (consulting, contracting, managed services) needs a commercial license. The GNOME extension is GPL-2.0-or-later.

Contributing

Help make it better

Bug reports, ideas and pull requests are welcome. A few habits keep a change easy to review, and safe for a tool that deletes and overwrites files on both sides.

  1. 1

    Open an issue first

    For anything beyond a typo. A rejected PR costs you more than a rejected issue; check the README's Status and Not planned sections too.

  2. 2

    Set up

    Go 1.26 or later. If the tests fail on a clean checkout, that is a bug: report it.

  3. 3

    One concern, tests with it

    Two unrelated fixes are two PRs. Tests run on temporary folders and in-process servers, never a real share or your home.

  4. 4

    Green before review

    Every check passes; a flaky one is said so, not rerun until it passes. The PR says what changes for a user; its title is a type(scope): summary commit.

$ git clone https://github.com/fqazzazee/shuttle.git && cd shuttle
$ pre-commit install        # optional; CI runs the same checks
$ make lint && make test
$ make lint-extension && make test-extension   # for the GNOME extension

How contributions are licensed

shuttle is source-available under the PolyForm licenses, and its maintainer also grants commercial ones. By opening a pull request, you agree that your contribution may be distributed under all of those terms. Contributions to the GNOME extension are under the GPL-2.0-or-later, as the extension is. If you cannot agree, say so in the PR before it is reviewed.

Found a security issue? Do not open an issue: report it privately, as SECURITY.md says.