Why use duplicity for backups?
It is a thin wrapper around common tools: gnupg for cryptography,
tar(1)
for archiving, and rsync for file synchronisation.
These are very widely used and widely available programs. They work on almost any platform.
And these programs (plus your encryption key) are all you need to get to your back up if duplicity
is not available.
duplicity
just makes it easier to create, verify, maintain and extract back ups.
My set up assumes there are three kinds of machines:
- A NAS or server that stores the back ups (and sync with some cloud provider)
- Machines you want to backup.
- A keyring machine where you keep your NAS key and a keyring of all the public keys of all machines you backup.
A full backup is made every month, and incremental backups are made every day. You can easily tweak the scheduling below.
Set up a NAS key pair
Generate a NAS gpg key pair on the keyring machine:
gpg --expert --full-gen-key
Set options: 9: ECC and ECC, 1: Curve 25519, never expire, realname: $hostname backup, email: root@$hostname.local.
Note the fingerprint of the NAS key (NASFP
) and export it:
gpg --armour --export NASFP
Set up a NAS to store backups
We will refer to this machine as NAS for short; it is just the machine where you will store your backups.
- Create a backup share.
- Create a machines group with no access except read only to backup share.
- Create a user for each machine you wish to back up.
- Enable rsync access.
- Create a directory in backup share with full control by that user.
I also synchronise the backup directory to an external cloud provider.
Set up back up on a machine
Create a per-machine key pair
sudo gpg --homedir=/root/.gnupg --expert --full-generate-key
Set options: 9: ECC and ECC, 1: Curve 25519, never expire, realname: $hostname backup, email: root@$hostname.local.
Note the fingerprint of the machine keyring (MACHINEFP
). Export it and import it locally to verify signed backups
sudo gpg --homedir=/root/.gnupg --list-keys --with-fingerprint
sudo gpg --homedir=/root/.gnupg --armour --export MACHINEFP >/tmp/key.asc
On the keyring host, import this key and set trust.
Paste in exported NAS public key (from the keyring host) and set trust:
sudo gpg --homedir=/root/.gnupg --import
sudo gpg --homedir=/root/.gnupg --edit-key NASFP
Responses: trust, 5, y, save
Create a ssh key for the machine:
sudo ssh-keygen -t ed25519 -f /root/.ssh/id_backup -N ''
Copy it to the backup host, fix up permissions on ~
and ~/.ssh
then do:
sudo ssh -i /root/.ssh/id_backup -vv $(hostname -s)@NAS
Check authentication works and accept the host key of the NAS.
Create exclusion list, these are things you do not want to backup:
sudo tee /root/backup.exclude <<EOF
/bin
/dev
/lib
/lib32
/lib64
/libx32
/media
/mnt
/proc
/run
/sbin
/sys
/tmp
/usr
/var/lock
/var/tmp
**/.*password-store
**/.ssh
**/.gnupg
**/.cache
**/Downloads
/etc/*shadow*
/etc/master.passwd
/etc/spwd.db
EOF
I prefer not to backup the OS, downloads, caches or any key material over the network. Key material I back up separately.
Create backup script in /root/backup
and its configuration
/root/backup.conf
. In /root/backup.conf
(below) update the NAS= variable to
the fingerprint of the NAS key fron the keyring machine (NASFP
). Update the
default hostname, and the hosts fingerprint from above (MACHINEFP
). Replace
NAS with the hostname of your NAS or backup server and the appropriate path.
Contents of /root/backup.conf
:
# config: fill these in
hostname=bar
HOST=MACHINEFP
NAS=NASFP
if [ -z "$hostname" ]; then
hostname=foo
fi
if [ -z "$BACKPATH" ]; then
BACKPATH="rsync://$hostname@NAS//volume1/backup/$hostname"
POSTBACKUP=":"
fi
# end of config
Contents of /root/backup
:
#!/bin/sh
CFG=/root/backup.conf
opts=""
. "$CFG"
export HOME=/root
export PATH=/usr/local/bin:$PATH
opts="--archive-dir /root/.cache/duplicity --name $hostname"
opts="$opts --ssh-options='-oIdentityFile=/root/.ssh/id_backup'"
opts="$opts --hidden-encrypt-key $NAS --hidden-encrypt-key $HOST --sign-key $HOST"
opts="$opts --exclude-if-present .nodump --exclude-filelist /root/backup.nodump --exclude-filelist /root/backup.exclude"
if [ "$(uname -s)" = OpenBSD ]
then
find / -flags nodump >/root/backup.nodump
else
echo consider running:
echo "find . -xdev -a \( -type f -o -type d \) -exec lsattr {} \; | grep '^-*d' | cut -d' ' -f2-"
touch /root/backup.nodump
fi
export PASSPHRASE=''
export SIGN_PASSPHRASE=''
if [ "$1" = full ]
then
duplicity full $opts / $BACKPATH
$POSTBACKUP
elif [ "$1" = inc ]
then
duplicity incremental $opts / $BACKPATH
$POSTBACKUP
elif [ "$1" = verify ]
then
duplicity verify $opts -v4 $BACKPATH /
elif [ "$1" = status ]
then
duplicity collection-status $opts $BACKPATH
elif [ "$1" = ls ]
then
duplicity list-current-files $opts $BACKPATH
elif [ "$1" = restore ]
then
duplicity restore $opts $BACKPATH $2
elif [ "$1" = prune ]
then
duplicity cleanup $opts --force $BACKPATH
duplicity remove-all-but-n-full 6 $opts --force $BACKPATH
duplicity remove-all-inc-of-but-n-full 3 $opts --force $BACKPATH
else
echo "usage: $0 [full|inc|verify|status|ls|restore path|prune]"
fi
Then run a full backup: sudo /root/backup full
Check verify the backup on the keyring host (replace NASFP
with the fingerprint of the NAS key):
PASSPHRASE='' duplicity list-current-files --encrypt-key NASFP rsync://NAS//volume1/backup/MACHINE
Schedule Regular Backups
Here’s how to schedule a monthly and daily backup. If you want a different frequency, adapt the last method.
There are roughly three ways to schedule daily and monthly backups, depending on which *nix you are dealing with.
- If
/etc/cron.daily
exists as a directory- Create
/etc/cron.daily/zz-backup
and write/root/backup inc
in it - Create
/etc/cron.monthly/zz-backup
and write/root/backup full
in it
- Create
- If
/etc/daily
exists and is a script- Append
/root/backup inc
to/etc/daily.local
- Append
/root/backup full
to/etc/monthly.local
- Append
- Otherwise, run
sudo crontab -e
and add:
HOME=/root
15 3 1 * * /root/backup full
17 10 2-31 * * /root/backup inc
Enjoy!