«

»

Jul
30
2007

Web hosting backup via rsync and dar

I finally set up (again) an automatic off-site incremental backup of my dreamhost account.

Last time, after a disk crash, I set up a new linux box and restored everything from the backup; indeed almost everything. I forgot to restore just one thing: the backup scripts :(

The idea is to sync the remote server files with a local directory and then make an incremental backup on the local computer. Subsequently copy back the archive, having so an historically memory of every changes both on local and remote machine.

Thanks to fullo for checking this stuff.


Step 0: Directory and users setup

Let’s say you want to backup stuff located on foo.com and the user assigned by provider on the remote server is user.

I created a backup user of my home linux box; this isn’t required, but I prefer to not mix my own stuff and the backup files.

So the directories layout is:

~/foo.com
~/foo.com/copy
~/foo.com/archives

Step 1: SSH setup

To automate all things, you need to be able to connect through SSH without using a password. The steps required are describe here and are valid in general, not just for dreamhost accounts. Anyway, I’m copying just a list of commands here, without explanations.

On your home box, login as debug user and write these lines; you will be prompted for password twice:

ssh-keygen -t rsa -f foo.com.rsa -N ''
scp foo.com.rsa.pub user@foo.com:~/
ssh user@foo.com

mkdir .ssh
cat foo.com.rsa.pub >> .ssh/authorized_keys
rm foo.com.rsa.pub

chmod go-w ~
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Logout and test whether SSH is working:

ssh user@foo.com -i foo.com.rsa

It should open an ssh session without asking you the password.

Step 2: MySQL dump

While logged on the remote server, do:

mkdir -p ~/backup/archives
cd ~/backup

With your preferred (or available) editor write into ~/backup/dumpmysql.sh on the remote server:

#!/bin/sh
mysqldump -u yourmysqluser -pyourmysqlpassword \\
     -h mysqlhost databasename \\
     | bzip2 > ~/backup/databasename.sql.bz2

If you have more databases, you could just add a line for each database to backup, or may be you prefer to store more database backup in one single file.

chmod u+x ~/backup/dumpmysql.sh
~/backup/dumpmysql.sh
crontab -e

The last command will open a text editor; write a new line like this:

0 0 * * * ~/backup/dumpmysql.sh

Starting by now, this command will be executed every day at midnight. Further details and examples can be found here.

Step 4: Syncing local copy with remote server files

Before syncing the files, make a list of files you don’t want to backup: for example I don’t want cache files in the archives. So create two files; call the first ~/foo.com/exclude.lst and the latter ~/foo.com/include.lst. For example, in the first I wrote:

backup/archives
logs
*cache

In the other:

wp-cache*

The first line of the exclude file is very important, as it excludes the backup copied back to the server; without it you’ll end up in multiple self-replicating copies of your backup, one inside the other! The last line of include file is useful for preventing the exclusion of the wp-cache wordpress plugin from backups, which would otherwise match with the *cache line in the exclude file.

Now you’re ready for the first sync:

sync -az -e "ssh -l user -i /home/backup/foo.com.rsa" \\
     --exclude-from=~/foo.com/exclude.lst \\
     --include-from=~/foo.com/include.lst \\
     user@foo.com: ~/foo.com/copy

Step 5: Make a base archive

Create a list of file to not compress: it’s not mandatory, but it’ll speed up a lot the process whilst increasing very few the actual archive size. Create a file called nocompress.lst, containing the masks matching the files to archive uncompressed, for example (pay attention to write everything on a single line):

-Z *.jp*g -Z *.gif -Z *.swf -Z *.avi -Z *.flv -Z *.mov
-Z *.wmv -Z *.wma -Z *.mp*g -Z *.jar -Z *.zip
-Z *.gz -Z *.bz2 -Z *.Z -Z *.rar -Z *.ace -Z *.png
-Z *.7z -Z *.JP*G -Z *.GIF -Z *.SWF -Z *.AVI
-Z *.FLV -Z *.MOV -Z *.WMV -Z *.WMA -Z *.MP*G
-Z *.JAR -Z *.ZIP -Z *.GZ -Z *.BZ2 -Z *.RAR -Z *.ACE
-Z *.PNG -Z *.7Z -Z *.msi -Z *.dmg -Z *.iso

You are now ready to create the base archive and transfer it on the server:

ARCHIVE=~/foo.com/archives/`date +%Y-%m-%d`_base
dar -y -c $ARCHIVE \\
     -R ~/foo.com/copy/ \\
     `cat ~/foo.com/nocompress.lst`
scp -i ~/foo.com/foo.com.rsa \\
     $ARCHIVE user@foo.com:~/backup/archives

Step 6: Schedule syncing and backup

Create the script ~/foo.com/sync.sh:

#!/bin/sh
USER=user
HOST=foo.com
BASEDIR=~/foo.com
SSHKEY=$BASEDIR/foo.com.rsa
SYNCDIR=$BASEDIR/copy
ARCHIVESDIR=$BASEDIR/archives
ARCHIVE=$ARCHIVESDIR/`date +%Y-%m-%d`

pushd $BASEDIR > /dev/null

rsync -az -e "ssh -l $USER -i $SSHKEY" --delete \\
     --exclude-from=$BASEDIR/exclude.lst \\
     --include-from=$BASEDIR/include.lst \\
     $USER@$HOST: $SYNCDIR

LASTARCHIVE=`ls -t $BASEDIR/archives/* \\
     | head -n1 \\
     | sed -e 's/.[0-9]*.dar$//'`
dar -y -c $ARCHIVE -X *.dar \\
     -A $LASTARCHIVE \\
     -R $SYNCDIR \\
     `cat $BASEDIR/nocompress.lst`
rsync -az -e "ssh -l $USER -i $SSHKEY" --delete \\
     $ARCHIVESDIR/ $USER@$HOST:~/backup/archives

popd > /dev/null

Last things to do: copy these files on server for future reference and schedule the backup:

chmod u+x ~/foo.com/sync.sh
scp -i ~/foo.com/foo.com.rsa ~/foo.com/* user@foo.com:~/backup
crontab -e

In the text editor write a line like the following:

0 2 * * 7 ~/foo.com/sync.sh

Backup will now run every Sunday at 2:00AM.

1 comment

  1. Roberisco says:

    I wanted to comment and thank the author, good stuff

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>