Backups mit Restic und Raspberry Pi

  Martin Brodbeck   Lesezeit: 8 Minuten  🗪 6 Kommentare

Restic ist eine gute und schnelle Alternative zu Borg. Grund genug, sich das einmal genauer anzusehen.

backups mit restic und raspberry pi

Leserkommentare zum letzten Artikel Backups mit Borg und Raspberry Pi haben mich dazu veranlasst, das Setup noch etwas zu verfeinern. Dazu habe ich aus Geschwindigkeitsgründen Borg über Bord geworfen und durch Restic sowie den dazugehörigen REST-Server ersetzt. Außerdem kommt zum automatischen Einhängen der Backup-Festplatte nun systemd anstelle von autofs zum Einsatz.

REST-Server (Raspberry Pi)

Der REST-Server ist eine schnelle Alternative zu SSH als Übertragungsprotokoll und muss auf dem Raspberry Pi als Serverkomponente von Restic installiert werden. Im Heimnetz können wir auch erst mal auf eine TLS-Verschlüsselung verzichten – das Backup selbst ist ja immerhin schon verschlüsselt.

Damit der Dienst nicht mit root-Rechten laufen muss, erstellen wir einen User restic, der sich nicht anmelden können muss:

useradd -s /usr/sbin/nologin restic

Glücklicherweise gibt es vom REST-Server auch Binaries für die ARM Architektur des Pi. Wir laden also das Binary herunter, entpacken es und kopieren es nach /usr/local/bin/:

wget https://github.com/restic/rest-server/releases/download/v0.12.0/rest-server_0.12.0_linux_arm64.tar.gz
tar xzf rest-server_0.12.0_linux_arm64.tar.gz
mv rest-server_0.12.0_linux_arm64/rest-server /usr/local/bin/

Damit der REST-Server automatisch gestartet wird und mit den Berechtigungen des erstellten restic-Users läuft, erstellen wir eine systemd-Datei und platzieren sie unter /etc/systemd/system/rest-server.service. Die Datei hat folgenden Inhalt:

[Unit]
Description=Rest Server
After=syslog.target
After=network.target

# if you want to use socket activation, make sure to require the socket here
#Requires=rest-server.socket

[Service]
Type=simple
# You may prefer to use a different user or group on your system.
User=restic
Group=restic
ExecStart=/usr/local/bin/rest-server --path /srv/restic --no-auth
Restart=always
RestartSec=5

# The following options are available (in systemd v247) to restrict the
# actions of the rest-server.

# As a whole, the purpose of these are to provide an additional layer of
# security by mitigating any unknown security vulnerabilities which may exist
# in rest-server or in the libraries, tools and operating system components
# which it relies upon.

# IMPORTANT!
# The following line must be customised to your individual requirements.
ReadWritePaths=/srv/restic

# Makes created files group-readable, but inaccessible by others
UMask=027

# If your system doesn't support all of the features below (e.g. because of
# the use of an older version of systemd), you may wish to comment-out
# some of the lines below as appropriate.
CapabilityBoundingSet=
LockPersonality=true
MemoryDenyWriteExecute=true
NoNewPrivileges=yes
PrivateTmp=yes
PrivateDevices=true
PrivateUsers=true
ProtectSystem=strict
ProtectHome=yes
ProtectClock=true
ProtectControlGroups=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectProc=invisible
ProtectHostname=true
RemoveIPC=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6
RestrictSUIDSGID=true
RestrictRealtime=true
# if your service crashes with "code=killed, status=31/SYS", you probably tried to run linux_i386 (32bit) binary on a amd64 host
SystemCallArchitectures=native
SystemCallFilter=@system-service

# Additionally, you may wish to use some of the systemd options documented in
# systemd.resource-control(5) to limit the CPU, memory, file-system I/O and
# network I/O that the rest-server is permitted to consume according to the
# individual requirements of your installation.
#CPUQuota=25%
#MemoryHigh=bytes
#MemoryMax=bytes
#MemorySwapMax=bytes
#TasksMax=N
#IOReadBandwidthMax=device bytes
#IOWriteBandwidthMax=device bytes
#IOReadIOPSMax=device IOPS, IOWriteIOPSMax=device IOPS
#IPAccounting=true
#IPAddressAllow=

[Install]
WantedBy=multi-user.target

Wie man sieht, habe ich hier --path /srv/restic und ReadWritePaths=/srv/restic angegeben. Das ist der Pfad zum Restic-Repository bzw. zu der Festplatte, die wir – wie im letzten Artikel – automatisch dann mounten, wenn darauf zugegriffen wird. Anstelle von autofs machen wir das dieses Mal aber mit systemd-Bordmitteln. Dazu bedarf es nur eines Eintrages in /etc/fstab:

LABEL="Restic" /srv/restic ext4 defaults,noatime,x-systemd.automount,x-systemd.idle-timeout=10 0 0

Das impliziert natürlich, dass die Festplatte eine ext4-Partition mit dem Label „Restic“ hat (etwa: mkfs.ext4 -L Restic -m 2 /dev/sda1 – Vorsicht, Daten gehen verloren!). Außerdem muss der restic-User darauf Lese-/Schreibrechte haben.

Jetzt müssen systemd noch die Änderungen mitgeteilt und die Automountfunktion gestartet werden. Außerdem wird der REST-Server aktiviert und gestartet:

systemctl daemon-reload
systemctl start srv-restic.mount
systemctl enable --now rest-server

Der REST-Server ist nun aktiv und lauscht an Port 8000 auf Restic-Kommandos.

Restic (Client)

Um immer die aktuellste Resic-Version zu haben, bietet es sich an, diese ebenfalls als Binary von der Github-Seite herunterzuladen. Ausführbar gemacht wird die Datei dann nach /usr/local/bin/ verschoben:

# wget https://github.com/restic/restic/releases/download/v0.15.2/restic_0.15.2_linux_amd64.bz2
# bunzip2 restic_0.15.2_linux_amd64.bz2
# chmod +x restic_0.15.2_linux_amd64
# mv restic_0.15.2_linux_amd64 /usr/local/bin/restic

Das Backup-Skript aus dem Borg-Artikel muss natürlich etwas angepasst werden. Bei der Gelegenheit wurde es etwas verschlankt und das Passwort ist jetzt nicht mehr direkt enthalten. Vielmehr wurde es in die Datei /root/.restic.pw ausgelagert. Diese gehört root:root und ist mittels chmod 600 /root/.restic.pw auch nur für diesen lesbar. Auf einem Notebook/PC mit verschlüsselter Platte ist das für mich akzeptabel. Das Backup-Skript selbst kann dann beispielsweise so aussehen:

#!/usr/bin/env bash

export RESTIC_REPOSITORY=rest:http://192.168.178.52:8000

# some helpers and error handling:
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
usage() {
echo "usage: backup_restic.sh [-t [home | system]] | [-h]"
}

backup_home() {
export SNAPSHOT_PATH=/.snapshots/restic-home

btrfs subvolume snapshot -r /home $SNAPSHOT_PATH
sync

cd $SNAPSHOT_PATH

restic backup \
--host `hostname` \
--exclude-caches \
--exclude '*/.cache/*' \
--tag home \
--one-file-system \
--password-file $HOME/.restic.pw \
--cleanup-cache \
.

cd /tmp

btrfs subvolume delete $SNAPSHOT_PATH

restic forget \
--prune \
--host `hostname` \
--tag home \
--password-file $HOME/.restic.pw \
--keep-daily 7 \
--keep-weekly 2 \
--keep-monthly 3

}

backup_system() {
export SNAPSHOT_PATH=/.snapshots/restic-system

btrfs subvolume snapshot -r / $SNAPSHOT_PATH
sync

cd $SNAPSHOT_PATH

# Backup the home directories into an archive named after
# the machine this script is currently running on:
restic backup \
--exclude-caches \
--exclude 'root/.cache' \
--exclude 'dev' \
--exclude 'proc' \
--exclude 'sys' \
--exclude 'var/run' \
--exclude 'lost+found' \
--tag system \
--one-file-system \
--password-file $HOME/.restic.pw \
--cleanup-cache \
. /boot /boot/efi

cd /tmp

btrfs subvolume delete /.snapshots/restic-system

restic forget \
--prune \
--host `hostname` \
--tag system \
--password-file $HOME/.restic.pw \
--keep-daily 7 \
--keep-weekly 2 \
--keep-monthly 3
}

## MAIN
bkuptype=""
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

Das Repository muss vorher natürlich einmalig initialisiert werden. Das können wir gut händisch auf dem Client-Rechner erledigen:

# restic -r rest:http://mypiserver:8000 -p /root/.restic.pw init

Eine Bemerkung noch zu `RESTIC_REPOSITORY`. Hier habe ich bewusst die IPv4-Adresse des Raspberry Pi angegeben. Zunächst hatte ich hier den Hostnamen angegeben. Die Verbindung für ein (umfangreiches) Backup wurde dann über die IPv6-Adresse aufgebaut. Über Nacht scheint sich diese jedoch geändert zu haben (*) und der Backupvorgang konnte nicht abgeschlossen werden. Das war zwar kein großes Problem, weil eine erneute Ausführung an der unterbrochenen Stelle einfach weiter gemacht hat, aber unschön war das auf jeden Fall. Wenn man hier einfach die statische IPv4-Adresse angibt, umgeht man dieses Problem.

Übrigens kann man bei Restic problemlos ein und dasselbe Repository für mehrere Rechner verwenden. Restics Deduplizierung funktioniert dann auch über Rechnergrenzen hinweg. Ein Feature, das Borg meines Wissens nach so nicht bietet.

Für weitere Restic-Befehle sei auf die umfangreiche Dokumentation des Projekts verwiesen.

(*): So jedenfalls meine Vermutung. Das Borg-Backup hatte übrigens das gleiche Problem.

Quelle: https://restic.net/

Tags

backup, restic, raspberry

lutz
Geschrieben von lutz am 23. Mai 2023 um 10:25

Es gibt "e2label" um ein FS-Label ohne Datenverlust zu ändern. Wenn "--one-file-system" benutzt wird, sind --excludes auf /sys, /proc, /dev unnötig, da sie idR eigene (virt.) Dateisysteme bilden.

joerg
Geschrieben von joerg am 24. Mai 2023 um 10:44

und dein Fazit Martin? Borg oder Restic? :)

Martin
Geschrieben von Martin am 25. Mai 2023 um 21:29

Restic. :) Ist schneller und bietet angenehme Details wie z. B. Tags. Nur der Arbeitsspeicherbedarf scheint mir deutlich höher zu sein. Bei meinem VPS oder auch dem Raspberry Pi selbst (also nicht wenn er als Backupserver fungiert, sondern wenn ich von ihm ein Backup mache) muss ich da etwas aufpassen.

Helux
Geschrieben von Helux am 5. September 2023 um 20:50

Hallo, was macht genau "systemctl start srv-restic.mount" ?

Michael
Geschrieben von Michael am 11. November 2023 um 12:44

Im angepassten Script aus dem borg-Artikel taucht btrfs auf .... die Festplatte wird in der Anleitung aber mit ext4 formatiert und daher geht das nicht. Wie ist das allenfalls zu ändern? Danke.

Martin
Geschrieben von Martin am 5. Januar 2024 um 10:07

Ja, die Backup-Festplatte wird mit ext4 formatiert. Das ist ok so. Das System, von dem Backups gemacht werden, ist hingegen mit Btrfs formatiert. Hier werden die Snapshots erstellt, um einen konsistenten Zustand während des Backup-Prozesses zu haben.