Borg backups from my archlinux workstation to a synology NAS

Since I setup my workstation with sway (see this article), the last thing I need to add is a backup solution. On OS X you have Time Machine, on Windows there’s also a backup system but on linux you have to roll your own.

# Research

I’m a fervent user of syncthing, a continuous file synchronization program. This runs on my Android phone, my workstation, my home computer and a raspberry pi. It helps syncing my photos and my passwords on every devices. But this is not a backup solution in my opinion. At first, I wanted to use this syncthing tool to backup the whole computer and by digging I found out that syncthing users usually backed up their syncthing databse with rsync or Borg. I never heard of Borg and went to read their documentation. It’s one of the most used software to do backups as it supports:

# Setting the synology up

On the synology, I used the SynoCommunity borgbackup package. Once installed, go create a shared folder named “borgbackup”. Then, the trick is to create a specific RSA key that will be used by SSH to authenticate the backup user. You can create a specific group/user for your backups, I was lazy to do so and I don’t think it has much benefits. I’ll therefore use my computer username to connect. Once the key is created with ssh-keygen -f ~/.ssh/id_rsa_borgbackup -C "borg@pm.me", I copied the key to the synology in ~/.ssh/authorized_keys. Note that the synology home directory needs 755 permissions, as always ssh permissions should be:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Now there’s a trick for borg which is to restrict the ssh key to the borg command using in the ~/.ssh/authorized_keys file:

command="/usr/local/bin/borg serve --restrict-to-path /volume2/borgbackup",restrict ssh-rsa AAAAKEYHERE... borg@pm.me

Once setup you can try to connect with ssh using:

ssh -vvvT -i ~/.ssh/id_rsa_borgbackup user@host

Where host is your synology ip/hostname, -vvvT is to test the connection using debug verbosity.

# Setting borg updates on archlinux

You can use borg directly, I think that using borgmatic helps with the configuration as everything is setup through a yaml file.

As usual, I’m not fond of running things via root and I’ll backup only things in my home directory. Therefore I’ll use borgmatic as my usual username.

Let’s first install borgmatic.

Then, my configuration file is located in ~/.config/borgmatic/config.yaml, you can find the whole configuration here and the configuration reference on the borgmatic website.

Let’s go over the important bits:

location:
    # Backup source
    source_directories:
        - /home/soyuka

    # Repository, redactedhostname is the synology location
    repositories:
        - soyuka@redactedhostname:/volume2/borgbackup/syk-xp5

    # The borg executable path on the synology
    remote_path: /usr/local/bin/borg

    # You'll see later that we can use `--dry-run` to see what actually gets
    # backed-up, I chose to remove non-useful data, mostly dotfiles, caches and
    # browser configurations
    patterns:
        - '- /home/*/Downloads'
        - '- /home/*/.cache'
        - '- /home/*/.cargo'
        - '- /home/*/.circleci'
        - '- /home/*/.cmake'
        - '- /home/*/.*-gyp'
        - '- /home/*/.fzf*'
        - '- /home/*/.hyperdrive'
        - '- /home/*/.ipfs*'
        - '- /home/*/.kube'
        - '- /home/*/.local'
        - '- /home/*/.minikube'
        - '- /home/*/.mozilla'
        - '- /home/*/.npm'
        - '- /home/*/.nvm'
        - '- /home/*/.phpls'
        - '- /home/*/.pipewire-media-session'
        - '- /home/*/.pki'
        - '- /home/*/.PlayOnLinux'
        - '- /home/*/.pm2'
        - '- /home/*/.rustup'
        - '- /home/*/.standard-c14-cache'
        - '- /home/*/.steam*'
        - '- /home/*/.step'
        - '- /home/*/.symfony'
        - '- /home/*/.tor-browser'
        - '- /home/*/.vmware'
        - '- /home/*/.vscode-oss'
        - '- /home/*/.wine'
        - '- /home/*/.yarn'
        - '- /home/*/.config/chromium'
        - '- /home/*/.config/Slack'
        - '- /home/*/.config/WebTorrent'
        - '- /home/*/.config/Cypress'
        - '- /home/*/.config/Beaker Browser'
        - '- /home/*/.config/lutris'
        - '- /home/*/.config/obs-studio'
        - '- /home/*/.config/Dat Desktop'
        - '- /home/*/.config/IPFS Desktop'
        - '- /home/*/.config/VirtualBox'
        - '- /home/*/.config/discord'
        - '- /home/*/.config/Keybase/Cache'
        - '- /home/*/.config/Code - OSS'
        - '- /home/*/.antigen'
        - '- /home/*/.tmux/plugins'
        - '- /home/*/Documents/My Games'
        - '- /home/*/.vim/plugged'

    # Some patterns we exclude from the backup
    exclude_patterns:
        - '*node_modules*'
        - '*vendor*'
        - '*var/cache'

storage:
    # Change how ssh works using our previously setup key
    ssh_command: ssh -p specialport -i ~/.ssh/id_rsa_borgbackup

Now even if you have no clue what to ignore, just set up the ssh_command with the repository and initialize the borg repository using:

borgmatic -v2 init --encryption repokey --storage-quota 512G

-v2 is for verbose (we may need to see SSH issues), we’ll use a repokey encryption strategy (other exist see here for more informations). I used a storage quota of 512G which is twice the amount of my SSD.

At this point you’ll enter a passphrase that’ll be used to encrypt the backup. This key can be specified as the environment variable BORG_PASSPHRASE for later commands. For example, let’s do a dry-run backup:

BORG_PASSPHRASE=redacted borgmatic --verbosity 1 --files --dry-run

Adapt the patterns configuration to your needs and when you like it, remove the --dry-run argument to backup.

# Automatic backups

On Archlinux, I’m using systemd, and I’ll setup borgmatic using systemd timers. On the borgmatic documentation they’ll propose two files:

I used both and put them under ~/.config/systemd/user. Note that as I’m not running this as root, I have to remove some of the security flags, the borgmatic.service looks more like this:

[Unit]
Description=borgmatic backup
Wants=network-online.target
After=network-online.target
ConditionACPower=true

[Service]
Type=oneshot

# Certain borgmatic features like Healthchecks integration need MemoryDenyWriteExecute to be off.
# But you can try setting it to "yes" for improved security if you don't use those features.
MemoryDenyWriteExecute=no

# Lower CPU and I/O priority.
Nice=19
CPUSchedulingPolicy=batch
IOSchedulingClass=best-effort
IOSchedulingPriority=7
IOWeight=100

Restart=no
# Prevent rate limiting of borgmatic log events. If you are using an older version of systemd that
# doesn't support this (pre-240 or so), you may have to remove this option.
LogRateLimitIntervalSec=0

# Delay start to prevent backups running during boot. Note that systemd-inhibit requires dbus and
# dbus-user-session to be installed.
ExecStartPre=sleep 1m
ExecStart=systemd-inhibit --who="borgmatic" --why="Prevent interrupting scheduled backup" /usr/bin/borgmatic --syslog-verbosity 1

Last but not least, I’ll add the BORG_PASSPHRASE environment variable using systemctl --user edit bormatic.service and by adding:

[Service]
Environment="BORG_PASSPHRASE=redacted"

This will be added to the service. Use systemctl enable --user --now borgmatic.timer to enable the timer which runs daily by thefault. You can also execute the service right now by executing systemctl start --user borgmatic .

# When did the backup last run?

Backups are good but only when you’re sure that they do run. To do so, I’ll just check the journalctl --user borgmatic.service. When a backup has run, the last lines will be:

Sep 29 10:49:56 syk-xp5 borgmatic[3233766]: INFO Archive consistency check complete, no problems found.
Sep 29 10:49:56 syk-xp5 borgmatic[3233766]: INFO
Sep 29 10:49:56 syk-xp5 borgmatic[3233766]: INFO summary:
Sep 29 10:49:56 syk-xp5 borgmatic[3233766]: INFO /etc/borgmatic/config.yaml: Successfully ran configuration file
Sep 29 10:49:56 syk-xp5 systemd[1]: borgmatic.service: Succeeded.
Sep 29 10:49:56 syk-xp5 systemd[1]: Finished borgmatic backup.

Let’s just grab the date at which Finished bormatic backup. and add this date to my bottom waybar:

In .config/waybar/scripts/backup:

journalctl --user -u borgmatic.service --no-pager | grep -i 'Finished borgmatic backup.' | awk '{print $1 " " $2 " " $3}'

In the waybar config:

    "custom/backup": {
      "format": "{} ⏲️",
      "interval": 3600,
      "exec": "~/.config/waybar/scripts/backup"
    }

Which outputs the last backup date :).

Hope this helps! You can find all my configuration files on github/soyuka/dotfiles.