I find restic a convincing tool for encrypted incremental backups.
It supports a huge number of backends - in the following sftp is used.
As an example, I show how I backup my ~/.mail (which is fetched by mbsync in maildir format).
Before we can store our data, we have to initialize a restic repository:
restic -r sftp:user@remotehost:/path/to/storage/mail init
Restic will now let you set the encryption passphrase.
Now we can start our first backup operation:
restic -r sftp:user@remotehost:/path/to/storage/mail backup ~/.mail --exclude=".notmuch/" --exclude="*.mbsyncstate"
The exclude arguments in this example are used to avoid copying the state files of mbsync and the index created by notmuch.
Subsequent backups are issued the same way and are performed in an incremental way.
Each backup is represented by a snapshot in the restic repository.
List all snapshots:
restic -r sftp:user@remotehost:/path/to/storage/mail snapshots
If we want to restore a snapshot, we just retrieve the hash with the above command and issue a restore:
restic -r sftp:user@remotehost:/path/to/storage/mail restore HASH --target /tmp/restore-mail
Another convenient way to access the backups is the ability to use fuse mounts:
restic -r sftp:user@remotehost:/path/to/storage/mail mount /mnt/restic-mail
Read password from gpg-encrypted file
I usually don’t want to remember/type/paste my encryption passphrase, so let’s store it in a file encrypted with our gpg key.
Using bash process substitution (not /bin/sh compatible), we can then operate on our repository like this:
restic -p <(gpg -dq ~/.restic-password.gpg) -r ...
Now we just have to decrypt the password file using our gpg passphrase (or query a running gpg-agent process).
Note that with this approach, the encryption passphrase appears in the process list - so maybe don’t do this in multi user environments.
If you want to trigger your backups with cron or systemd-timers, you might be looking for a way to automatically provide the encryption passphrase.
This can be done by storing the passphrase in the RESTIC_PASSWORD shell variable, but please make sure that’s really what you want to do.