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:

  1. A NAS or server that stores the back ups (and sync with some cloud provider)
  2. Machines you want to backup.
  3. 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.

  1. Create a backup share.
  2. Create a machines group with no access except read only to backup share.
  3. Create a user for each machine you wish to back up.
    1. Enable rsync access.
    2. 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.

  1. If /etc/cron.daily exists as a directory
    1. Create /etc/cron.daily/zz-backup and write /root/backup inc in it
    2. Create /etc/cron.monthly/zz-backup and write /root/backup full in it
  2. If /etc/daily exists and is a script
    1. Append /root/backup inc to /etc/daily.local
    2. Append /root/backup full to /etc/monthly.local
  3. Otherwise, run sudo crontab -e and add:
HOME=/root
15      3       1       *       *       /root/backup full
17      10      2-31    *       *       /root/backup inc

Enjoy!