Search code examples
shellsynchronizationcronrsyncweb-deployment

Writing an rsync shell script on Mac to continuously sync local directory with remote web server


I need to set up a shell script on Mac OS X Mountain Lion to sync a local directory to a remote directory (web server) using either an SSH connection (tunnel) or SFTP and have it run continuously every 30 seconds.

I also need to exclude certain files or folders from being synced.

The syncing would be unidirectional (mac -> webserver).

The basic parameters I need to have implemented are as follows:

Local path: /Volumes/path/to/local/directory
Remote server: example.com
username: someUser
password: somePassword
Remote path: /path/from/server/root/to/htdocs
Files to exclude: '.ht*', '*.sublime-*'
Folders to exclude: 'cache','administrator/cache'

I would also need help writing the crontask and adding it to my system to execute automatically.

Any help would be greatly appreciated.


Solution

  • Here's what I would do:

    First, test that you can use ssh (login with user name and password):

    $ ssh example.com
    ^D
    

    Create an SSH key:

    $ ssh-keygen
    

    (don't enter a password)

    This will create the ~/.ssh/id_rsa (private key) and ~/.ssh/id_rsa.pub (public key files)

    You'll need to transer the public key (id_rsa.pub) to your remote server (example.com) and then on the remote server, do the following:

    $ cat id_rsa.pub >> ~/.ssh/authorized_keys
    $ rm id_rsa.pub
    ^D
    

    This adds the public key to the set of authorised keys.

    You'll now be able to use ssh to connect to your remote server without having to use a username and password.

    Next would be to use the rsync command, the following should suffice:

    $ rsync -avz -e ssh 
         --exclude '*.ht*' --exclude '*.sublime-*' --exclude 'cache/' 
         --exclude 'administrator/cache'
         [email protected]:/directory/on/server /directory/on/local
    

    (should be all on one line)

    Now, once you've satisfied that this works for you, you want to put that command into a shell script (rsync_script.sh)

    Then, you can use launchctl to schedule it:

    In ~/Library/LaunchAgents/, create com.example.rsync.plist

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.example.rsync</string>
        <key>KeepAlive</key>
        <true/>
        <key>ProgramArguments</key>
        <array>
            <string>/bin/sh</string>
            <string>/path/to/rsync_script.sh</string>
        </array>
        <key>StartInterval</key>
        <integer>30</integer>
    </dict>
    </plist>
    

    Couple of gotchas:

    • Make sure that the rsync_script.sh is executable, i.e. do chmod 755 /path/to/the/rsync_script.sh
    • Make sure that the user which created the SSH keys is the same user as sets up the launchd plist.