Skip to content

Instantly share code, notes, and snippets.

@apsun
Last active September 2, 2023 19:40
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apsun/f8d3bfec507cd08875e3bc4f72dea91e to your computer and use it in GitHub Desktop.
Save apsun/f8d3bfec507cd08875e3bc4f72dea91e to your computer and use it in GitHub Desktop.
Backup files using duplicity to Backblaze B2

duplicity -> Backblaze B2

Daily systemd timer to backup the contents of my filesystem to Backblaze B2. As-written, it will keep up to a year's worth of backups, performing one full backup every month. This script was tested with duplicity 2.1.0.

Configure the script

Create a B2 bucket and an application key with read/write permissions to that bucket. Configure object lock with a sufficiently long period (I use 3x the full backup period) to ensure that ransomware won't be able to nuke your backups. Also ensure the 'list all bucket names' option is enabled (unless you want to use the B2 SDK directly - the S3 SDK requires it for whatever reason). Update env.sh and include.txt with the appropriate values.

Install the service

# Ensure boto3 python package is installed
# Run the following commands as root

install -Dm600 env.sh /etc/duplicity/
install -Dm644 include.txt /etc/duplicity/
install -Dm644 duplicity-backup.service /etc/systemd/system/
install -Dm644 duplicity-backup.timer /etc/systemd/system/
install -Dm755 duplicity-backup.sh /usr/local/bin/
systemctl enable --now duplicity-backup.timer
[Unit]
Description=Run duplicity backup
After=network-online.target nss-lookup.target
[Service]
Type=simple
ExecStart=duplicity-backup.sh backup
#!/bin/bash
set -euo pipefail
. /etc/duplicity/env.sh
export AWS_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY
export PASSPHRASE
# usage: backup
backup() {
duplicity \
backup \
--include-filelist '/etc/duplicity/include.txt' \
--full-if-older-than 1M \
--verbosity 8 \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
'/' \
"${S3_URL}"
duplicity \
cleanup \
--force \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
"${S3_URL}"
duplicity \
remove-all-but-n-full 12 \
--force \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
"${S3_URL}"
}
# usage: list
list() {
duplicity \
list-current-files \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
"${S3_URL}"
}
# usage: verify <abs/rel path to file>
verify() {
duplicity \
verify \
--path-to-restore "$(realpath --relative-to '/' "$1")" \
--compare-data \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
"${S3_URL}" \
"$(realpath "$1")"
}
# usage: restore <abs/rel path to file>
restore() {
duplicity \
restore \
--path-to-restore "$(realpath --relative-to '/' "$1")" \
--s3-endpoint-url "${S3_ENDPOINT_URL}" \
"${S3_URL}" \
"$(realpath "$1")"
}
"$@"
[Unit]
Description=Run daily duplicity backup
After=network-online.target nss-lookup.target
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
S3_URL='boto3+s3://<YOUR_BUCKET_NAME>'
S3_ENDPOINT_URL='https://s3.us-west-002.backblazeb2.com'
AWS_ACCESS_KEY_ID='<YOUR_KEY_ID>'
AWS_SECRET_ACCESS_KEY='<YOUR_APPLICATION_KEY>'
PASSPHRASE='<YOUR_ENCRYPTION_PASSWORD>'
- /home/foobar/.cache
- /home/foobar/.go
- /home/foobar/.cargo
- /home/foobar/.rustup
- /home/foobar/.android
- /home/foobar/.gradle
- /home/foobar/.local/share/Trash
- /home/foobar/Downloads
+ /home
+ /etc
+ /usr/local
- **
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment