Serie: NAS mit ODROID-HC4 - Teil 2: Borg

Mo, 11. Oktober 2021, Martin Brodbeck

Mit dieser Artikelserie soll das Einrichten eines kleinen, günstigen NAS erläutert werden. Linux basierte Clients im Haushalt sollen darauf ihre Backups ablegen. Damit eine defekte NAS-Festplatte keinen Daten-GAU verursacht, werden die Daten per RAID1 gespiegelt. Der generische Ansatz (kein Fertigsystem) soll uns dabei helfen, auch andere Wünsche an das NAS zu erfüllen, wie z. B. ein Calibre Server.

Es sind folgende Teile geplant:
1. Hardware und Betriebssystem
2. Backups mit Borg
3. Calibre Server
4. Samba Server

Subvolume @backup

Um das RAID auch für andere Datenhaltungsaufgaben zu verwenden und diese sauber voneinander zu trennen, erstellen wir ein Subvolume, dediziert für unsere Backups:

# mount /dev/sda /mnt
# btrfs subvolume create /mnt/@backup
# umount /mnt

Damit das Subvolume automatisch eingehängt wird, erstellen wir noch das Verzeichnis /mnt/backup und fügen folgenden Eintrag in `/etc/fstab` hinzu:

[…]
/dev/sda1 /mnt/backup btrfs defaults,nofail,noatime,compress=zstd,subvol=@backup 0 0

Die Optionen können natürlich nach Belieben modifiziert werden. Ich habe mich für eine Kompression mittels des zstd-Algorithmus entschieden. nofail bewirkt, dass das System auch startet, wenn es beim Einhängen Probleme gibt. Wenn man sich einen Reboot ersparen will, mountet man das Subvolume nun einfach einmalig mit mount /mnt/backup (als root).

Borg Backup

Nach Installation des Pakets borgbackup erstellen wir einen User borg, dem die Backupdaten auf dem NAS gehören und gegen den sich die Borg-Clients authentifizieren.

# useradd -m borg

Natürlich wollen wir, dass borg der Owner für die Backups ist:

# chown borg:borg /mnt/backup

Falls noch nicht geschehen, erstellen wir jetzt auf den Clients, von denen wir Backups erstellen möchten, SSH-Schlüssel für root (ssh-keygen). Für root deshalb, weil je nach Backupzweck Zugriff auf Systemdaten oder die Daten anderer Benutzer notwendig ist. Die public keys speichern wir alle in der Datei ~/.ssh/authorized_keys von borg.

Um den Schaden zu begrenzen, falls Clients kompromittiert werden, kann man die erlaubten Kommandos für borg einschränken. Hierzu ist für jeden SSH-Key in authorized_keys z. B. folgendes voranzustellen:

command="borg serve --restrict-to-path /path/to/repo",restrict ssh-rsa AAAAB3[...]

Von den Clients aus können wir nun je ein borg-Repository erstellen, in dem dann die Backups landen:

# borg init -e repokey borg@droidnas:/mnt/backup/`hostname`

Nun ist alles bereit für das Erstellen von Backups. Die Borg-Dokumentation erläutert hierzu mannigfaltige Möglichkeiten. Ich möchte hier kurz mein Backup-Skript vorstellen, das es erlaubt, Backups von /home und vom System (ohne home) zu machen. Die Systeme sind bei mir so eingerichtet, dass sie auch Btrfs als Dateisystem verwenden und separate Subvolumes für / und für /home verwenden. Mittels Snapshots wird vermieden, dass Änderungen von Dateien während des Backups zu inkonsistenten Zuständen führen. Darauf kann man natürlich auch verzichten, und muss bei den Backups eben entsprechend umsichtig vorgehen. Hier jedenfalls mein derzeitiges Backup-Skript:

#!/bin/bash

export BORG_REPO=ssh://borg@droidnas:22/mnt/backup/`hostname`
export DATETIME=`date +%Y%m%d-%H%M%S`
export BORG_PASSPHRASE='HierMeinKomplexesPasswort'

info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }

backup_home() {
    export SNAPSHOT_PATH=/home/.snapshots/home-$DATETIME
    BACKUP_PATH=/mnt/backup-home

    info "Starting backup of home dirs"
    btrfs subvolume snapshot -r /home $SNAPSHOT_PATH
    sync
    mount --bind $SNAPSHOT_PATH $BACKUP_PATH

    cd $BACKUP_PATH

    # Backup the home directories
    borg create                         \
        --progress                      \
        --stats                         \
        --compression zstd              \
        --exclude-caches                \
        --exclude '*/.cache/*'          \
                                        \
        ::"home-$DATETIME"              \
        *                               \

    cd /tmp

    #echo "Deleting snapshot"
    umount $BACKUP_PATH
    btrfs subvolume delete $SNAPSHOT_PATH

    info "Pruning repository"

    # Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
    # archives of THIS home backup. The 'home-' prefix is very important to
    # limit prune's operation to these archives and not apply to
    # other archives also:

    borg prune                          \
        --list                          \
        --prefix 'home-'                \
        --keep-daily    7               \
        --keep-weekly   4               \
        --keep-monthly  6               \

}

backup_system() {
    export SNAPSHOT_PATH=/.snapshots/system-$DATETIME
    BACKUP_PATH=/mnt/backup-system

    info "Starting backup of system dirs"
    btrfs subvolume snapshot -r / $SNAPSHOT_PATH
    sync
    mount --bind $SNAPSHOT_PATH $BACKUP_PATH

    cd $BACKUP_PATH

    # Backup the system directories
    borg create                         \
        --progress                      \
        --stats                         \
    --one-file-system               \
        --compression zstd              \
        --exclude-caches                \
        --exclude 'root/.cache'         \
    --exclude 'dev'                 \
    --exclude 'proc'                \
    --exclude 'sys'                 \
    --exclude 'var/run'             \
    --exclude 'lost+found'          \
                                        \
        ::"system-$DATETIME"            \
        . /boot                         \

    cd /tmp

    #info "Deleting snapshot"
    umount $BACKUP_PATH
    btrfs subvolume delete $SNAPSHOT_PATH

    info "Pruning repository"

    # Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
    # archives of THIS system backup. The 'system-' prefix is very important
    # to limit prune's operation to these archives and not apply to
    # other archives also:

    borg prune                          \
        --list                          \
        --prefix 'system-'              \
        --keep-daily    7               \
        --keep-weekly   4               \
        --keep-monthly  6               
}

usage() {
    echo "usage: backup_borg.sh [-t [home | system]] | [-h]"
}

## MAIN
bkuptape=""
while [ "$1" != "" ]; do
    case $1 in
        -t | --type )    shift
                 bkuptype=$1
                         ;;
        -h | --help )    usage
                         exit
                         ;;
        * )              usage
                         exit 1
    esac
    shift
done

if [ "$bkuptype" == "home" ]; then
    backup_home
elif [ "$bkuptype" == "system" ]; then
    backup_system
else
    usage
fi

Mittels backup_borg.sh -t system oder backup_borg.sh -t home (mit root-Rechten) können nun Backups vom System- oder vom Home-Subvolume gemacht werden. Das Skript kann beliebig angepasst oder erweitert werden, etwa wenn vorab noch Datenbanksysteme gestoppt werden sollen o. ä.

Teil 3 der Artikelserie ist etwas spezieller und richtet sich an die E-Bookleser. Das NAS soll dann den Nutzern des Heimnetzes die geballte E-Book-Sammlung präsentieren. Somit können direkt über den Browser der E-Reader die Bücher auf die Geräte geladen werden, ohne ein USB-Kabel in die Hand zu nehmen.