In a recent post I described how I improved the reliability of my file system backups by using the data replication capabilities inherent in the FreeBSD Zettabyte File System (ZFS). In this post I will explore Tarsnap, another tool I recently started to use to perform secure offsite backups of my most important files.
The versions for the software used in this post are as follows:
- FreeBSD 11.0-RELEASE
- tarsnap 1.0.37
The steps discussed assume that the FreeBSD Ports Collection is installed. If not, you can install it using the following command:
1 |
portsnap fetch extract |
If the Ports Collection is already installed, make sure to update it:
1 |
portsnap fetch update |
Okay, let’s get started. Okay, let’s get started. All commands are issued as the user root. While building the various ports you should accept all default configuration options unless otherwise instructed.
Create a Tarsnap account
Before installing Tarsnap I visited the Tarsnap registration page and created an account. Tarsnap operates on a prepaid basis, so you have to add some money to your account before you can start using it. The minimum amount is $5.00. Money will be deducted from your pre-paid amount based on the actual number of bytes stored and bandwidth used (after compression and data deduplication). Tarsnap prices are currently $.25 per Gigabyte per month for storage, and $.25 per byte for bandwidth.
Install Tarsnap
After creating an account it was time to install Tarsnap. First I made sure the Ports Collection was up to date:
1 |
portsnap fetch update |
Then proceeded with the install, accepting all default configuration options:
1 2 |
cd /usr/ports/sysutils/tarsnap make config-recursive install distclean |
Next, I ran tarsnap-keygen, a utility which registers my machine with the Tarsnap server and generates a key that is used to encrypt and sign the archives that I create. I needed to have the e-mail address and password I used to create my Tarsnap account handy when running this command. In following example I’ve registered a machine with the host name tarsnap-test:
1 |
tarsnap-keygen --keyfile /root/tarsnap-test.key --user iceflatline@example.com --machine tarsnap-test |
Note that if I had multiple machines containing files I wished to backup to Tarsnap, I would want create a separate key file for each machine.
By default tarsnap-keygen will create the key file /root/tarsnap.key. This can be changed by adding the option keyfile to specify a different location and/or key name. In the example above I’ve changed the name of my key file to tarsnap-test.key to help disambiguate keys in case I add additional machines to my Tarsnap account in the future.
Tarsnap creates the file /usr/local/etc/tarsnap.conf when installed. This config file is read by the tarsnap utility and specifies a number of default options, all of which will be ignored if the options in question are specified at the command line. Since I change the name of default key file, I revised the value for the option keyfile in /usr/local/etc/tarsnap.conf:
1 |
keyfile /root/tarsnap-test.key |
Note that you should store a copy of this key someplace safe. If you lose your Tarsnap key file(s), you will not be able to create new archives or access your archived data.
Using Tarsnap
After installing Tarsnap I was ready to create and backup my first archive. Tarsnap commands follow a syntax similar to the venerable tar utility. The -c option creates a new archive containing the specified files. The -f option specifies which file to write the archive to:
1 |
tarsnap -cf backup-20150729 pool_0/dataset_0/backup/ |
Performing subsequent backups of these files will go faster since Tarsnap’s deduplication feature will avoid sending data which was previously stored.
If I want to list all archives stored with Tarsnap I can use the following command:
1 |
tarsnap --list-archives | sort |
Adding one or more instance of the -v option to this command will make the output more verbose. For example, if -v is specified one or more times, the creation time of each archive is printed; if it is specified two or more times, the command line with which Tarsnap was invoked to create each archive is also printed.
If I want to list the files contained within a single archive I can use the following command:
1 |
tarsnap -tvf backup-20150729 | more |
The -t option is used to print to stdout the files stored in the specified archive; the -v option of course makes the output a little more verbose.
If I wanted to delete one or more archives I can use the -d option:
1 |
tarsnap -df backup-20150729 |
When the time comes to restore one or more files from Tarsnap I have a couple of options. For example, I can recover all files contained in a particular archive using the following command. In this example, I’ve extracted all files contained in the archive backup-20150729 to /tmp where I can recover one of more files:
1 2 |
cd /tmp tarsnap -xf backup-20150729 |
Or I can extract just one of the directories in this archive:
1 2 |
cd /tmp tarsnap -xf backup-20150729 pool_0/dataset_0/backup/foo-directory/ |
Note here that you must exclude the leading / from the directory you’re restoring from. So in this case, instead of /pool_0/dataset_0/some-directory/, it should be pool_0/dataset_0/backup/some-directory.
Or regress even further into the archive to recover a single file if desired:
1 2 |
cd /tmp tarsnap -xf backup-20150729 pool_0/dataset_0/backup/foo-directory/foo-file |
Finally, if for whatever reason I no longer wish to use Tarsnap on this machine I can invoke the nuke option, which will delete all of the archives stored:
1 |
tarsnap --nuke |
To make sure you’re really serious, Tarsnap will ask you to type the text “No Tomorrow” when using this command.
Okay, after getting comfortable with the Tarsnap commands and backing up files manually for a couple of days, I created this ugly little script that creates a daily archive of a specified directory; looks for any archives older than 30 days and deletes them; and, logs its output to the file /home/iceflatline/cronlog:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#!/bin/sh ### BEGIN INFO # PROVIDE: # REQUIRE: # KEYWORD: # Description: # This script is used to perform backups using the tarsnap utility. The number of backups to retain is defined in the variable retention. # Author: iceflatline <iceflatline@gmail.com> # # OPTIONS: # -c: Create an archive containing the specified files # -d: Delete the specified archive # -f: Archive name ### END INFO ### START OF SCRIPT backup_prefix=backup retention=30 # Full paths to the following utilities are needed when running the script from cron. date=/bin/date grep=/usr/bin/grep sed=/usr/bin/sed sort=/usr/bin/sort tarsnap=/usr/local/bin/tarsnap xargs=/usr/bin/xargs backup_old=`$tarsnap --list-archive | $grep "$backup_prefix" | $sort -r | $sed 1,${retention}d | $sort | $xargs -n 1` backup_today="$backup_prefix-`date +%Y%m%d`" dir_0=/pool_0/dataset_0/backup/ log=/home/iceflatline/cronlog # Create a blank line between the previous log entry and this one. echo >> $log # Print the name of the script. echo "tarsnap.sh" >> $log # Print the current date/time. $date >> $log echo >> $log # Look for today's backup and, if not found, create it. if $tarsnap --list-archives | $sort | $grep "$backup_today" > /dev/null then echo "Today's backup '$backup_today' already exists." >> $log else echo "Taking today's backup: $backup_today" >> $log $tarsnap -cf $backup_today $dir_0 >> $log 2>&1 fi # echo >> $log # Remove backup(s) older than the value assigned to $retention. echo "Attempting to destroy old backups..." >> $log if [ -n "$backup_old" ] then echo "Destroying the following old backup:" >> $log echo "$backup_old" >> $log $tarsnap --list-archives | $grep "$backup_prefix*" | $sort -r | $sed 1,${retention}d | $sort | $xargs -n 1 $tarsnap -d -f >> $log 2>&1 else echo "Could not find any backups to destroy." >> $log fi # Mark the end of the script with a delimiter. echo "**********" >> $log # END OF SCRIPT |
I wrote the script to /home/iceflatline/bin/tarsnap.sh where I maintain some other scipts and made it executable:
1 |
chmod +x /home/iceflatline/tarsnap.sh |
Then added the following cron job to the crontab under user root. The script runs every day at 0800 local time:
1 2 |
# Run tarsnap backup script everyday at 0800 0 8 * * * /home/iceflatline/bin/tarsnap.sh |
Conclusion
Well, that’s it. A short post describing my experiences using Tarsnap, an easy, secure and inexpensive solution for performing offsite backups of my most important files.
References
https://www.tarsnap.com/gettingstarted.html
https://www.tarsnap.com/man-tarsnap.1.html
There are a couple of similar scripts listed at http://www.tarsnap.com/helper-scripts.html .
I came across a relatively new FreeBSD port called tarsnap-periodic “Simple way of making tarsnap backups using the periodic system” It appears to based off of zfs-periodic “Scripts to take zfs snapshots with periodic on FreeBSD” Looks promising!
Oclair, oh very cool! Thanks for passing this along.