rsync is a utility that provides fast incremental file transfer. This allows us to keep directories and files synchronised between servers whilst only transferring the minimum required data. This is often employed during code deployment scenarios from one environment to another.
It is preferable to use the -e option to specify a remote shell to use, namely ssh. This will ensure that the file transfers are encrypted and performed over SSH.
In our deployment scenario there are two servers, venus and earth. Both are webservers, and have content at /var/www/example.com/htdocs. venus is our test server, and earth is production. We’d like to deploy our content from venus to earth. This deployment could be automated (think continuous integration), or even scripted for simple deployments, but for the purposes of this tutorial we’ll just manually issue the commands as required. This is being performed on CentOS 6.4 with SELinux enabled.
I’ll start off by creating some simple “content” on venus:
|
|
venus ~ # mkdir -p /var/www/example.com/htdocs venus ~ # touch /var/www/example.com/htdocs/{1,2,3,4,5}.html venus ~ # ls -l /var/www/example.com/htdocs total 0 -rw-r--r--. 1 root root 0 Nov 28 11:53 1.html -rw-r--r--. 1 root root 0 Nov 28 11:53 2.html -rw-r--r--. 1 root root 0 Nov 28 11:53 3.html -rw-r--r--. 1 root root 0 Nov 28 11:53 4.html -rw-r--r--. 1 root root 0 Nov 28 11:53 5.html |
On earth, I’ll just create the empty content directory:
|
|
earth ~ # mkdir -p /var/www/example.com/htdocs |
Create a user/group on both servers that will be used for deployment. deploy@venus will allow interactive logins to push content to deploy@earth. deploy@earth will only allow the specific remote-side rsync command to run. This will be defined later in ~/.ssh/authorized_keys. For now, just create the users and groups:
|
|
venus ~ # groupadd -g 8080 deploy venus ~ # useradd -m -d /home/deploy -s /bin/bash -u 8080 -g deploy -c "Deployment User" deploy venus ~ # passwd deploy Changing password for user deploy. New password: Retype new password: passwd: all authentication tokens updated successfully. |
|
|
earth ~ # groupadd -g 8080 deploy earth ~ # useradd -m -d /home/deploy -s /bin/bash -u 8080 -g deploy -c "Deployment User" deploy earth ~ # passwd deploy Changing password for user deploy. New password: Retype new password: passwd: all authentication tokens updated successfully. |
Set ownership on our deployment directories. Do this on both servers:
|
|
# chown -R deploy:deploy /var/www/example.com/htdocs |
It is obvious that any permissions set here should not interfere with the way your web server actually serves its content. You may need to set up ample group permissions for the deploy group, then add the webserver user to that group.
The first step in setting up our file syncronisation is to configure password-less SSH login from deploy@venus to deploy@earth. Having no passphrase on the SSH key we’re about to create is the reason for limiting command access via ~/.ssh/authorized_keys.
Start with key generation as deploy@venus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
venus ~ # su - deploy deploy@venus ~ $ ssh-keygen -t rsa -b 2048 -N '' -f ~/.ssh/id_rsa Generating public/private rsa key pair. Created directory '/home/deploy/.ssh'. Your identification has been saved in /home/deploy/.ssh/id_rsa. Your public key has been saved in /home/deploy/.ssh/id_rsa.pub. The key fingerprint is: a3:8a:87:14:00:bb:3d:61:a8:71:ef:96:dd:35:0b:eb deploy@venus.local The key's randomart image is: +--[ RSA 2048]----+ |o | |.o | |+.+ | |.*.o | |o o.. S o | | .o o o = o | | . .+ o o . | | .o.. . | | ... E | +-----------------+ |
As you can see, a 2048-bit RSA key has been generated.
Next, create ~/.ssh on earth, and copy the public key to deploy@earth:.ssh/authorized_keys:
|
|
deploy@venus ~ $ cat .ssh/id_rsa.pub | ssh deploy@earth 'mkdir -p .ssh; cat >> .ssh/authorized_keys' The authenticity of host 'earth (192.168.122.13)' can't be established. RSA key fingerprint is 11:70:df:c3:f7:b0:32:9a:ec:0e:b6:11:1a:0f:d8:d3. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'earth,192.168.122.13' (RSA) to the list of known hosts. deploy@earth's password: |
On earth, we now need to fix SELinux contexts and permissions on deploy@earth:
|
|
deploy@earth ~ $ chcon -Rt ssh_home_t ~/.ssh deploy@earth ~ $ chmod 700 ~/.ssh deploy@earth ~ $ chmod 600 ~/.ssh/authorized_keys |
We can now check that password-less SSH is working:
|
|
deploy@venus ~ $ ssh deploy@earth hostname earth.local |
Next, we can use rsync to perform a dry-run of our deployment with the --dry-run option. Specifying the -v option twice shows the remote command that will be executed:
|
|
deploy@venus ~ $ rsync --dry-run -Cavvz -e 'ssh' /var/www/example.com/htdocs/ deploy@earth:/var/www/example.com/htdocs opening connection using: ssh -l deploy earth rsync --server -vvnlogDtprCze.iLs . /var/www/example.com/htdocs sending incremental file list delta-transmission enabled ./ 1.html 2.html 3.html 4.html 5.html total: matches=0 hash_hits=0 false_alarms=0 data=0 sent 120 bytes received 30 bytes 300.00 bytes/sec total size is 0 speedup is 0.00 (DRY RUN) |
The remote command can be seen above - rsync --server -vvnlogDtprCze.iLs . /var/www/example.com/htdocs. We can populate deploy@earth:.ssh/authorized_keys with this command against deploy@venus‘s public key in the file, limiting deploy@venus to ONLY be able to execute the remote rsync command. We need to drop one of the -v‘s and -n (--dry-run) from the remote command too. Modify deploy@earth:.ssh/authorized_keys as appropriate:
|
|
deploy@earth ~ $ cat .ssh/authorized_keys from="192.168.122.12",command="rsync --server -vlogDtprCze.iLs . /var/www/example.com/htdocs" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0NsYHxzdYSG8XQDxja/Ebgo5sjdBAsEidARfyoBQCirCO/JBEhG+oFOl0x+4LcxOHjObVVpzrWmq8nxvahXTcCKbrhYOpxWsr0T7sWUa6WLPwm3iM1W0qS36WrRPx1ZD3pbqFGRubyo/evj1w/MvprtrPpItm8LFEAV+UiXWiZuK/6lG7Daxy2dWW9ru5R2Xx8ZJX9sgXMEH+W0u68H0mnNiUsrRGkXc9HWDYZeV1Hd2TtwF90r+12gdc4S5iaV7hydhG8qC142YoUAqiFIeDb3WU8/1H+FigYcjOPmwN1SvqeHVZNVoLDsqD5t34ibR/BHvkPu82s2U6ktTxlcaOQ== deploy@venus.local |
Note that I also add the from= configuration parameter so that only connections from venus are permitted. Now, the password-less SSH configuration is locked down so that any connections from deploy@venus can only run the remote rsync command.
Test from deploy@venus:
|
|
deploy@venus ~ $ rsync -Cavz -e 'ssh' /var/www/example.com/htdocs/ deploy@earth:/var/www/example.com/htdocs sending incremental file list ./ 1.html 2.html 3.html 4.html 5.html sent 285 bytes received 110 bytes 790.00 bytes/sec total size is 0 speedup is 0.00 |
Running the command again should not transfer any changes (as there haven’t been any):
|
|
deploy@venus ~ $ rsync -Cavz -e 'ssh' /var/www/example.com/htdocs/ deploy@earth:/var/www/example.com/htdocs sending incremental file list sent 102 bytes received 12 bytes 228.00 bytes/sec total size is 0 speedup is 0.00 |
And we can now verify that earth has the files:
|
|
deploy@earth ~ $ ls -l /var/www/example.com/htdocs total 0 -rw-r--r--. 1 deploy deploy 0 Nov 28 11:53 1.html -rw-r--r--. 1 deploy deploy 0 Nov 28 11:53 2.html -rw-r--r--. 1 deploy deploy 0 Nov 28 11:53 3.html -rw-r--r--. 1 deploy deploy 0 Nov 28 11:53 4.html -rw-r--r--. 1 deploy deploy 0 Nov 28 11:53 5.html |