Duplicity Wrapper Script

For many years I relied upon rdiff-backup to securely backup all my servers and desktop machines, including routers, laptops, etc. Sadly, the rdiff-backup project was abandoned, and the search for a replacement began in earnest. Luckily, a similar (and better) replacement exists: Duplicity!

Like rdiff-backup, duplicity is best operated by a wrapper script from a cron job, to keep everything running in a smooth and automatic fashion. To this end, I’ve updated my rdiff-backup Bash wrapper script to use duplicity instead. The script takes care of process locking and excluding files which shouldn’t go into the archive. In hopes it’ll be useful to someone, you can download it, or view it:

#!/bin/bash
#
VERSION=1.1.0
# 2015/01/05
#
# Please do not put spaces in the name of this script,
# the lock file is based on $0 and spaces break things.
#
# You will want something like this in ~/.ssh/config, where the virtual host
# name corresponds to the NAME variable below:
#
# Host my-backup
#	Hostname backupserver.my.lan
#	User backup
#	Identityfile /root/.ssh/id_rsa_my-backup
#	Compression yes
#	Protocol 2
#
#
#
# Changelog:
#
# 2015/01/05 - Aaron Ten Clay <[email protected]>
#              Add '/root/.cache/duplicity' as the explicit cache path
#              Add '/root/.cache/duplicity' to default exclusionlist
#              Used 'NAME' variable in backup path
#              Added default 'full if older than 4 months' argument
#
# 2014/05/13 - Aaron Ten Clay <[email protected]>
#              Add '/mnt' to default exclusionlist, again. Should not have been removed.
#
# 2014/03/27 - Aaron Ten Clay <[email protected]>
#              Changed to duplicity since rdiff-backup is now unmaintained
#
# 2011/09/05 - Aaron Ten Clay <[email protected]>
#              Corrected output redirection and added filtering for harmless error messages
#
# 2011/04/10 - Aaron Ten Clay <[email protected]>
#              Updated order of include/exclude arguments to capture kernel config
#              Added output filtering via Grep to ignore SpecialFileError messages
#
# 2009/07/20 - Aaron Ten Clay <[email protected]>
#              Added rudimentary version checking
#
# 2009/02/21 - Aaron Ten Clay <[email protected]>
#              Fixed spelling error
#
# 2009/01/20 - Aaron Ten Clay <[email protected]>
#              Repaired grammar in error messages
#
# 2009/01/17 - Aaron Ten Clay <[email protected]>
#              Repaired remote version error message
#


# Quick customization parameters
NAME="my-backup"
TARGET="rsync://${NAME}/root"
PASSPHRASE="super-secret-passphrase-here"

# Main script

function check_script_version {
	latest=$(wget --no-check-certificate -qO- "https://www.aarontc.com/projects/duplicity-wrapper-script/version-check?version=${VERSION}")
	if [[ "x${latest}" == "x" ]]; then
		echo "Notice: Version check failed"
	else
		if [[ "${latest}" != "latest" ]]; then
			echo "Notice: Version check returned: ${latest}"
		fi
	fi
}

function sigcaught () {
	rm -f "$lockfile"
	echo "Error: caught interrupt" >&2
	exit 2
}



# Here begins the actual work

# Exit if using uninitialized variable
set -o nounset

check_script_version

lockfile="/tmp/$(basename $0).pid"

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
	trap sigcaught INT TERM EXIT
	export PASSPHRASE

	duplicity \
		--full-if-older-than 4M \
		--archive-dir /root/.cache/duplicity \
		--exclude /root/.cache/duplicity \
		--exclude /dev \
		--exclude /media \
		--exclude /mnt \
		--exclude /opt \
		--exclude /proc \
		--exclude /sys \
		--exclude /tmp \
		--exclude /usr/portage \
		--exclude /usr/tmp \
		--include /usr/src/linux/.config \
		--exclude /usr/src \
		--exclude /var/cache \
		--exclude /var/log \
		--exclude /var/tmp \
		--asynchronous-upload \
		--name "${NAME}" \
		--no-print-statistics \
		--volsize 100 \
		$* \
		"/" \
		"${TARGET}" \
		2>&1

	rm -f "$lockfile"
	trap - INT TERM EXIT
else
	echo "Error: Failed to acquire lockfile: $lockfile, held by PID $(cat $lockfile)" >&2
fi