Update: Before implementing this method you might want to look at duply which uses gpg to implement the same functionality but does not need large image files.
We own a server which is used to keep e-mail and other personal data off the commercial cloud. Partly because of paranoia, partly because of the enjoyment of maintaining our own server.
We run the server ourselves so we have to backup all the software and configuration to get timely recovery after catastrophic failure. If you do the same, depending on the availability you want you will probably be running on a hardware RAID. But: Even that can fail, be it through software failure fucking your file system good or through some bigger hardware blackout. If the server going down is home to your e-mail, your dropbox-equivalent and your website you want to be able to get it back up as quickly as possible.
For this goal, our hosting provider allows for 100 GB of backups on one of their machines. It is vastly less than the 3 Tb of RAID5-storage on our server, but roughly covers the amount of data really vital to operating the server. We’re talking mysql databases, mail boxes, config files, websites hosted etc.
The big caveat is that the 100Gb of free backup space can only be accessed through FTP. This means:
- It’s not encrypted; everything can be read by our hoster. Not really desireable when you just spent hours on end making your system as safe as possible with encrypted disks.
- It does not preserve file permissions.
- It is too slow for large amounts of files. (We tried to run rsync on a curlftpfs-mounted ecryptfs-overlaid FTP share and it was just not usable).
Creation of the encrypted disk image
We decided to do things differently: As a backup target we use a disk image file (~95Gb), one copy of which lives on the local disk of our server. This disk image is encrypted using cryptsetup. I used the following commands to create the disk image (they are needed only once)
# create 95Gig file of zeros (takes time depending on disk speed) dd if=/dev/zero of=/backupimage.dat BS=1M COUNT=95000 # format it as an encrypted disk image cryptsetup luksFormat /backupimage.dat # open a loopback device for said image cryptsetup luksOpen /backupimage.dat backupvolume # format the volume mkfs.ext4 /dev/mapper/backupvolume # make a directory for the "disk" mkdir /backupvolume mount /dev/mapper/backupvolume /backupvolume
Now the encrypted image is mounted in /backupvolume. You can toy around with it, write some data to it etc. When you’re done, you should unmount the volume and close the loopback device:
umount /backupvolume cryptsetup luksClose backupvolume
The backup process
For the backup process I needed to automatize the process. Only automatic backups will be run regularly and only regularly running backups are good backups. To automatize, I need a foolproof way of starting and stopping the loopback device and uploading the data to the FTP server. For the time being I’m using three bash scripts:
1. Mount the encrypted backup volume
This script opens the loopback device and mounts the encrypted disk image to /backup. Note that the password for the crypted image is clear text. This is necessary because you want the backup to run automatically. Additionally, the script can only be read by root and once someone has root access to your server he can access all the data anyway.
#!/bin/bash if ! [ -a /dev/mapper/backupvolume ] # make sure loopback is closed then echo "password" | cryptsetup luksOpen /backupimage.dat backupvolume if mount /dev/mapper/backupvolume /backupvolume/ then echo mount successful exit 0 else # if we cannot mount we should close the loopback cryptsetup luksClose backupvolume echo "had problems mounting closed cryptloop device" exit 200 fi else # if we cannot even open the loopback there was an error echo "error" exit 200 fi
1.1. Back up
Now is the time you want to backup stuff to /backupvolume. Make sure you leave the directory after, otherwise the following will throw an error.
2. Unmount the encrypted backup volume
After backup you need to properly close the backup volume:
#!/bin/bash if [ -a /dev/mapper/backupvolume ] #make sure there is a cryptoloop then if ! umount /backupvolume #try to unmount it then # throw error if fail echo "unable to unmount" exit 200 else # otherwise go on and unhook the loopback if ! cryptsetup luksClose backupvolume then echo "luksClose failed" exit 200 else exit 0 fi fi fi
3. Upload the backup disk image to the FTP server
Once you have backed up to your image, the image file on your needs to be sent to the backup location. In our case that is an FTP server and if you want to use this method of backing up you are likely in a similar situation. For uploading data we use the following script:
#!/bin/bash HOST=<ftp-host> USER=<username> PASS=<password> MACHINE=<name of the machine> ftp -inv $HOST <<END >ftp.log user $USER $PASS put /backupimage.dat backupimage-$MACHINE.dat bye END if fgrep "226 Transfer complete" ftp.log then exit 0 else echo "FTP upload failed" exit 200 fi
In the next chapter: How to use these three scripts to backup your data automatically and be informed via e-mail whenever something goes wrong.