Psst .. using Git? Unlimited private repositories for just $5/month — Learn more...

Auto rsync local changes to remote server

When developing software that’s intended to run on a server, I like to edit the code directly on my laptop, but don’t want to run the development server locally.

Instead, I have a dev setup on a remote server, and copy the local changes as needed, using rsync to copy only the changed bits.

Running rsync is manual work, prone to errors and easy to forget. So I automated it by writing a shell script that runs it whenever I change the directory.

The Script

The script is pretty simple. It uses inotifywait (part of inotify tools on Linux) to detect changes in the current directory and runs a command when that happens. To avoid running multiple commands on a related sequence of events, the script waits a second to see if there are more events coming.

The script itself doesn’t assume which command needs to be run, so it’s useful beyond just triggering rsync. You can find the script on GitHub.

Example usage

When working on a project, I start the watch script with something like:

    onchange.sh rsync -avt --delete . server:/path/

Speeding up rsync+ssh

Since I’m running rsync frequently, I want it to be as quick as possible (even though it’s happening in the background). Since the changes are very small, most of the time spent is in initiating SSH connection to the remote server.

To minimise this, I’m using SSH connection multiplexing. I just ssh into the server, even if I don’t need to do anything there. This keeps the connection open. Subsequent rsyncs over ssh just reuse it.

Portability

Unfortunately, as this uses inotify tools directly, it’s not very portable to non-Linux systems. It’s easy to write the equivalent tool in, say, python using watchdog.

That’s left as an excercise to the reader ;-)

Update: there’s also lsyncd, a full-blown tool for live syncing local with remote folders.

8 comments

  1. Thanks for sharing this script, Senko! I’ve been thinking about writing something like this recently and now I don’t have to!

    Cheers!

  2. You could also do better and use a versioning system like git..

    • I use git daily, but it’d be a poor tool for the job in question.

      I use the above script while I’m developing code, while it’s still a mess, and I don’t want to create dummy commits just so I could sync it to the dev server.

      While I could squash those commits into a normal one to make a “real” on in the end, it’s more work (and more manual work, and slower), with no extra benefits.

  3. You could also add persistent connections with: “ControlPersist 4h” (or some other time). It keeps the “ControlMaster” alive for 4h, even after logging out!

  4. @Alexander:

    ControlPersist does not seem to work with OpenSSH_5.3p1
    Do you know when did that option got added up to ssh?

  5. Ah sorry, I believe it’s pretty recent. I’m running:
    ~ $ ssh -v
    OpenSSH_5.8p2, OpenSSL 1.0.0d 8 Feb 2011

    After some googling I found that it’s seems to be added in 5.6x, which is available for example in Ubuntu 11.04.

  6. ControlPersist is implemented since OpenSSH 5.6

    http://lwn.net/Articles/401422/