With B2 and systemd

In this configuration, Restic is configured via systemd template units, allowing one or more configurations to be created without duplicating the scripts used to manage it.

Care is taken to keep the B2 App Keys and Restic password file secure, using separate environment files to keep credentials from showing up in systemctl show and file permissions to prevent nosy folks discovering our details.

System configuration

Install Restic and prepare a local cache directory:

sudo apt install restic
sudo mkdir /var/lib/restic-backup

Create the systemd service unit /etc/systemd/system/restic-backup@.service:

[Unit]
Description=Perform Restic backup
Requires=network-online.target
After=network-online.target

[Service]
Type=simple
Environment=RESTIC_CACHE_DIR=/var/lib/restic-backup
ExecStart=/bin/sh -c 'exec restic backup --verbose --cache-dir $${RESTIC_CACHE_DIR} $${SOURCE_DIR}'

And corresponding timer /etc/systemd/system/restic-backup@.timer:

[Unit]
Description=Perform Restic backup
Requires=restic-backup@%i.service

[Timer]
OnCalendar=*-*-* 20:00:00
Persistent=true

[Install]
WantedBy=timers.target

To allow executing Restic with the correct environment variables, create the helper /usr/local/bin/restic-backup-env:

#!/bin/bash

main() {
  if [[ -z "$1" ]]; then
    echo "usage: $0 <unit template>" >&2
    exit 1
  fi

  local template="/etc/systemd/system/restic-backup@$1.service.d/environment"
  if [[ ! -f "$template" ]]; then
    echo "$0: template file $template doesn't exist; is the unit template configured correctly?" >&2
    exit 1
  fi

  export $(xargs <"$template")
}

main "$@"

Make it executable:

sudo chmod +x /usr/local/bin/restic-backup-env

For each job

Create a B2 Bucket, giving it a name, making files private, and enabling server-side encryption, but leave the object lock disabeld. Once created, verify in Lifecycle Settings that all file versions will be retained.

Create an App Key with the same name as the bucket, and allow it access to just the newly created bucket. It'll need Read and Write access, no File name prefix. Optionally set an expiry.

Create a new directory for the template unit, and lock down access, replacing values preceded with $ with their corresponding values:

sudo mkdir /etc/systemd/system/restic-backup@$name.service.d
sudo touch /etc/systemd/system/restic-backup@$name.service.d/{environment,local.conf}
openssl rand -hex 32 >/etc/systemd/system/restic-backup@$name.service.d/password
sudo chmod 0700 /etc/systemd/system/restic-backup@$name.service.d
sudo chmod 0600 /etc/systemd/system/restic-backup@$name.service.d/*

Edit /etc/systemd/system/restic-backup@$name.service.d/environment:

SOURCE_DIR=/backups
B2_ACCOUNT_ID=$app_key_id
B2_ACCOUNT_KEY=$app_key_secret
RESTIC_REPOSITORY=b2:$b2_bucket_name
RESTIC_PASSWORD_FILE=/etc/systemd/system/restic-backup@$name.service.d/password

Edit /etc/systemd/system/restic-backup@$name.service.d/local.conf:

[Service]
EnvironmentFile=/etc/systemd/system/restic-backup@cluster-data.service.d/environment

Initialise the new Restic repository:

$ sudo -s
> (. restic-backup-env $name; restic init)
> ^D

Now, enable the timer to make sure the backup runs on a schedule:

sudo systemctl enable --now restic-backup@$name.timer

Backlinks