Backupserver mit rotierenden außer Haus Festplatten
Inhaltsverzeichnis
1 Über diese Dokumentation
Diese Dokumentation enthält die Besonderheiten meiner Backup Einrichtung, die nicht in freier Dokumentation enthalten ist. (Man Pages etc.).
Einerseits da ich eine lange Betriebszeit der Lösung anstrebe und in 10 Jahren noch wissen will was ich wie und warum so eingerichtet habe und andererseits hege ich die Hoffnung, dass andere aus den Informationen nutzen ziehen können und ich damit den Einsatz freier Software und folglich die Erlangung informationeller Selbstbestimmung und digitaler Freiheit unserer Gesellschaft unterstütze.
Das Ziel ist kein How To und keine Schritt für Schritt Anleitung, sondern eine Ergänzung zu im Netz und freier Softwaredokumentation vorhandenen Informationen. Verweise auf diese werden ggf. gegeben.
Bei Fragen, Hinweisen, Fehlern oder kommerziellen Beratungs/Installations/Anpassungsbedarf bitte melden.
Diese Dokumentation ist lizenziert unter CC BY-SA 4.0. Der Quellcode unter GNU General Public License v3 or later.
2 Zielsetzung
Für die Sicherung aller unserer Geräte und um im Notfall eine idente, freie Austauschhardware für meinen Web/Emailserver zu haben habe ich einen Backupserver mit derselben Olimex A20 Hardware (freie Konstruktion) eingerichtet. Dieser kleine, sehr stromsparende ARM basierte SoC Server sichert automatisch laufend diverse Server und Laptops, PC's und Handys über das Netzwerk (Wlan, Lan, Internet) auf 3 externe verschlüsselte USB Festplatten. Zwei davon sind immer extern physikalisch getrennt verwahrt, während auf die andere laufend vom Server gesichert wird. Wöchentlich werden die Platten manuell rotiert. Auf den zu sichernden Geräten sollte einzig rsync und ssh mit passwortlosem Login notwendig sein. Das Backup sollte zentral vom Server ausgelöst, gesteuert und überwacht werden. Das erleichtert die Administration.
3 Hardware
3.1 Olimex A20-OlinuXino-MICRO wie Webserver, mit folgenden Unterschieden:
- blaues Gehäuse statt schwarz (zwecks Unterscheidbarkeit)
- kleinere 250mA Batterie, die 1400mAh des Webservers sind für eine USV überdimensioniert.
- T2 Prozessor statt dem A20. T hat einen größeren Temperaturbereich (Industrieausführung), ansonsten ident. T hat es zum Zeitpunkt als ich den Webserver kaufte noch nicht gegeben.
3.2 3 x 2,5'' externe USB Platten 4T
Die externen Festplatten werden am oberen USB Port 1, der 1000 mA liefert, angeschlossen. Der untere Port 2 liefert nur 523mA und ist daher zu schwach.
UAS funktioniert mit den Seagate Platten und dem Linux Kernel nicht zuverlässig und musste deaktiviert werden:
$ cat /etc/modprobe.d/blacklist_uas.conf options usb-storage quirks=0bc2:ab28:u
Im Olimex Kernel 5.10.180-olimex ist usb-storage nicht als Modul kompiliert, sonder statisch. Daher muss UAS mit Linux-Boot Kommandozeilenparametern deaktiviert werden. Dazu mit einem seriellen Kabel und screen Terminal booten
$ screen /dev/ttyUSB0 115200
und eine beliebige Taste drücken und in der u-boot Kommandozeile das einstellen:
$ setenv bootargs 'usb-storage.quirks=0bc2:ab28:u,059f:1093:u,1058:2621:u,0bc2:203a:u' $ saveenv
Im gestarteten Linux kann überprüft werden ob es funktioniert hat mit:
$ cat /proc/cmdline
Die WD Platten funktionieren mit uas.
Die Platten sind mit dm-crypt/luks verschlüsselt und mit ext4 Dateisystem formatiert. Es ist wichtig die Verschlüsselung und Formatierung auf dem A20 und nicht auf einem Laptop oder anderem Gerät mit mehr RAM zu machen, weil cryptsetup die RAM Größe bei luksFormat ermittelt und dann auch wieder für die Verschlüsselung braucht. Es kann also passieren, dass ein Gerät das mit viel RAM verschlüsselt wurde auf einem Gerät mit wenig Ram nicht mehr entschlüsselbar ist. siehe Zwecks Unterscheidbarkeit haben die Festplatten unterschiedliche Gehäusefarben, das Kaufdatum / Garantiezeit und Händler wird darauf notiert.
Zuerst wurden 2 Platten verwendet, aber später auf 3 geändert, da bei Defekten einer Platte eine neue mit den Daten kopiert werden muss und das Tage dauern kann, währenddessen kein Backup möglich ist. Mit 3 Platten gibt es keine Unterbrechungen des Backups wenn eine Platte defekt wird.
Das Schreiben einer kompletten 4 TB HDD dauert ca. 1,5 Tage. Das Datei basierte kopieren einer verschlüsselten 4 TB Platte dauert bis zu 3 Tage, da sie zuerst auch mit /dev/zero überschrieben werden muss und dann die Daten kopiert.
cryptsetup luksFormat /dev/sdX cryptsetup luksOpen /dev/sdX encrypted-external-drive dd if=/dev/zero of=/dev/mapper/encrypted-external-drive bs=64K status=progress mkfs.ext4 /dev/mapper/encrypted-external-drive mount /dev/mapper/encrypted-external-drive /tmp/neue_hdd rsync --info=progress2 -a /tmp/alte_hdd/rsnapshot /tmp/neue_hdd/
Alternativ ist bitweises Kopieren mit dd und ändern der UUID's möglich. Wichtig ist, dass die neue Platte gleich groß oder größer ist als die alte von der kopiert wird. Achtung: auch nominal gleich große Platten können eine unterschiedliche Anzahl Bytes haben. Daher beide Platten prüfen mit:
$ fdisk -l /dev/mapper/seagate Festplatte /dev/mapper/seagate: 3,64 TiB, 4000770252288 Bytes, 7814004399 Sektoren $ fdisk -l /dev/mapper/wdneu Festplatte /dev/mapper/wdneu: 3,64 TiB, 4000735821824 Bytes, 7813937152 Sektoren
- Kopieren:
Prüfen Devicenamen: dmesg in watch Modus und Platten nacheinander einstecken
$ sudo dmesg -w
- Klonen:
dd if=/dev/sdX of=/dev/sdY bs=32M status=progress
- Ändern UUID's:
der Luks Partition:
cryptsetup luksUUID /dev/sdc --uuid 8170ad52-0aac-4d1a-adaf-d15dca28dabb
des Dateisystems, e2fsck ist vorher notwendig, Achtung: tune2fs ist sehr langsam
e2fsck -f /dev/mapper/wdneu tune2fs /dev/mapper/wdneu -U 4efafebc-966a-4caa-9907-e5f3427ccd5c
Die Seagate Consumer Platten haben beide leider nur ein paar Jahre gehalten und auch die Lacie Rugged Platte war innerhalb der Garantiezeit von 3 Jahren defekt. Auch eine WD Elements SE Platte war bald defekt. Eine weitere WD Elements ist nach einem halben Jahr defekt geworden. Um Komplettausfälle aufgrund von Serienfehlern zu vermeiden ist es ratsam verschiedenste Hersteller / Typen für die Platten zu verwenden und auf eine lange Garantiezeit zu achten. Die Firma e-tec war erst nach Drohung mit Gewährleistung bereit nach Monaten interner Prüfung der beanstandeten Platte diese zu tauschen. Sie behaupten die Garantiezeit verlängert ein Tausch nicht. Sie ließen mich bei der Abholung einen Übernahmezettel unterschreiben ohne Hinweis auf den Vorbehalt zur Nachverrechnung im Kleingedruckten. Mediamarkt hat die Platte sofort anstandslos und unkompliziert im Markt umgetauscht.
Ein Wechsel/Versuch auf SSD ist noch ausständig.
3.3 interne SATA Platte
Ursprünglich 1 x vorhandene interne SATA HDD 320 GB Samsung HM329JI.
Im Jänner 2021 wurde eine neue SSD (SSD-WD-WDS120G2G0A Green SSD WDS120G2G0A, 120GB SSD, intern, 2.5" (6.4 cm), SATA 6Gb/s) eingebaut, und das Betriebssystem darauf neu installiert, da die microSD Karte defekt wurde.
4 Software
4.1 Betriebssystem
Installiert wurde wie auf dem Webserver Standard Debian Stretch, allerdings mit unverschlüsselter Root Partition ursprünglich auf der SD/MMC1 microSD Karte und dem von Olimex mit deren Image mitgelieferten u-boot. Von dem größeren SD/MMC2 SD Karten Schacht ist leider kein Betriebssystemstart möglich. (von Olimex dokumentiert)
Leider ist diese microSD Karte im Jänner 2021 defekt geworden, sodass eine Neuinstallation auf einer neuen SATA SSD notwendig war. u-boot blieb auf einer neuen microSD Karte. Es wurde wieder Debian Oldstable (Stretch) installiert, weil unter Buster cryptsetup mit aes-xts-plain64 cipher für die externen Platten aufgrund eines Bugs nicht funktionierte.
Diverse Absicherungen des Servers wurden konfiguriert / installiert.
Um ein versehentliches Schreiben auf das nicht eingehängte Mount-Verzeichnis der externen Platte und damit ein Vollschreiben der Root Partition zu vermeiden, wurde das Verzeichnis mit chattr schreibgeschützt.
Zur Erhöhung der Sicherheit und um Strom zu sparen werden die externen USB Platten vor dem Backup eingeschaltet und nach dem Backup wieder komplett abgeschaltet:
$ cat /usr/local/bin/mount-exthdd #!/bin/bash # exit 2 source getbkpdev source lockwait timeout=30 # seconds to wait for the device appearing lockfile=/var/lock/mount-exthdd.lock lockwait $lockfile 10 60 trap "rm -f ${lockfile}; exit" INT TERM EXIT echo $$ > ${lockfile} if mount | grep "/dev/mapper/exthdd_crypt" > /dev/null; then exit 0; fi if ! get_dev >/dev/null ; then # probably before powered off usb device, reload kernel module to turn it on again rmmod ehci_platform modprobe ehci_platform # wait for the device to appear i=0 until get_dev > /dev/null ; do sleep 10 let "i++" if [ $i -eq $timeout ]; then echo "timout searching for the device waited times: $i" exit 1 fi # echo "waiting... nr $i" done fi if ! get_dev > /dev/null; then echo "unable to find backup device" 1>&2 exit 1 fi cryptsetup luksOpen $(get_dev) exthdd_crypt --key-file=xxxx if [ $? ]; then mount /dev/mapper/exthdd_crypt /mnt/exthdd fi
$ cat /usr/local/bin/lockwait function dbg { # logger -id "$srcname.lockwait" -p syslog.debug "$1" # echo $1 } function lockwait () { lockfile=$1 sleeptime=$2 timeout=$3 scrname=$(echo $0 | awk -F "/" '{print $NF}') if [ -f $lockfile ]; then PID=$(cat $lockfile) dbg "lockfile $lockfile : andere PID=$PID eigene=$$" if [ $PID -ne $$ ]; then if kill -0 $PID; then t="waiting for '$lockfile' pid: $PID" logger -id $scrname -p syslog.info "$t" dbg "$t" i=0 while ps -p $PID >/dev/null 2>&1 do dbg "sleep $sleeptime nr $i" sleep $sleeptime let "i++" if [ $i -eq $timeout ]; then t="timeout waiting for '$lockfile' pid: $PID" logger -id $scrname -p syslog.err $t dbg "$t" exit 1 fi done dbg "$PID nicht mehr da" fi fi else dbg "lockfile $lockfile nicht vorhanden" fi }
$ cat /usr/local/bin/getbkpdev #!/bin/bash dev_schwarz=/dev/disk/by-uuid/xxxxxxx-xxxx-xxx-xxxx-xxxxxx dev_silber=/dev/disk/by-uuid/xxxxxxx-xxxx-xxx-xxxx-xxxxxx get_dev () { if test -b $dev_schwarz; then echo $dev_schwarz return 0 elif test -b $dev_silber; then echo $dev_silber return 0 else return 1 fi }
$ cat /usr/local/bin/umount-exthdd #!/bin/bash source getbkpdev timeout=10 # seconds to wait for the device powering off umount /mnt/exthdd && cryptsetup luksClose /dev/mapper/exthdd_crypt if [ $? -eq 0 ] && get_dev > /dev/null; then i=0 until udisksctl power-off -b $(get_dev) || [ $i -eq $timeout ]; do sleep 1 i=$(( i++ )) done fi
4.1.1 Instabilitäten
- Watchdog
Wegen seltenen plötzlichen Stillständen mit Schmierzeichen in /var/log/syslog wurde der Hardware Watchdog konfiguriert:
$ apt install watchdog
$ grep -i watchdog /etc/systemd/system.conf RuntimeWatchdogSec=10 #RebootWatchdogSec=10min ShutdownWatchdogSec=10min #KExecWatchdogSec=0 #WatchdogDevice=
$ reboot now
Watchdog testen mit künstlich ausgelösten Kernel Panic:
echo c > /proc/sysrq-trigger
- CPU Frequenz Governor
Diese Stillstände sind auch am Webserver aufgetreten und auch mit Tausch der Hardware nicht verschwunden. Es liegt die Vermutung nahe, dass es am Kernel liegt:
$ uname -r $ 5.10.180-olimex
Die Vermutung im Olimex Forum, dass es an der CPU Frequenz Steuerung liegt kann ich nicht bestätigen, da es auch nach der Umstellung auf Performance Governor (siehe unten) zu Stillständen kam. Olimex Forums Einträge zu dem Thema
Der Standard Governor scheint problematisch zu sein, und der Performance Governor verursacht kaum relevanten Strommehrverbrauch: https://linux-sunxi.org/Cpufreq
Daher wurde am 28.1.2024 das umgestellt:
$ cat /etc/default/cpufrequtils # valid values: userspace conservative powersave ondemand performance # get them from cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors GOVERNOR="performance"
4.2 Backup Software
Für die inkrementelle Sicherung täglich, wöchentlich, monatlich wird rsnapshot verwendet. BorgBackup wird nicht verwendet weil es nicht in Dateien, sondern in ein eigenes Container Format sichert. Allerdings ist für mich die Einfachheit, Solidität und direkter, langlebiger, zukunftssicherer Dateizugriff eine zentrales Kriterium eines Backups. Die Deduplizierung auf Byteebene die BorgBackup im Gegensatz zu rsnapshot bietet, ist bei unseren Daten nicht entscheidend relevant. Darüberhinaus bin ich der Meinung, dass die Deduplizierung eine separate Aufgabe des Dateisystems oder einer dedizierten Schicht zwischen Dateisystem und Anwendung ist. Leider sind die Programme dazu (btrfs, zfs etc.) für GNU/Linux nicht vorhanden bzw. noch nicht ausgereift.
Für rdiff-backup gilt Ähnliches (zumindest für die Inkrements), darüber hinaus scheint es derzeit nicht wirklich aktiv gepflegt/genutzt zu werden. rsnapshot ist im Aufbau recht einfach und setzt über Jahrzehnte bewährte, simple Unix Hausmittel wie Hardlinks, cp, rsync, mv, touch etc. ein.
Für die Auslösung, Steuerung und Überwachung der Sicherung werden cron, anacron und selbst erstellte Bash Skripte verwendet. Systemd wird abseits des Debian Standards nicht verwendet, da die Architektur nicht der Unix Philosophie entspricht.
Server die dauernd eingeschaltet sind und Endgeräte die nur sporadisch im Netz verfügbar sind benötigen eine separate Konfiguration:
4.2.1 Nicht andauernd eingeschaltete Geräte
Über cron wird regelmäßig geprüft ob das Gerät im Netz ist und nicht im Batteriebetrieb läuft (ansonsten leert das Backup die Batterie) und ob dieses an diesem Tag noch nicht gesichert wurde:
$ cat /etc/cron.d/backup_check_hosts PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # m h dom mon dow user command */2 * * * * root /usr/local/bin/backup_check_hosts
$ cat /usr/local/bin/backup_check_hosts #!/bin/bash hosts="host1 host2 host3" lockfile=/var/run/rsnapshot.pid debug=0 dbg () { if [ ! $debug == "0" ]; then echo $1 fi } if [ -f $lockfile ]; then if kill -0 $(cat $lockfile); then dbg "rsnapshot already running. $lockfile: PID $(cat $lockfile)" exit 0 fi fi for host in $hosts; do if nc -z -w 1 $host 22 &> /dev/null; then if [ $debug == "0" ]; then ssh $host /usr/bin/on_ac_power 2> /dev/null else ssh $host /usr/bin/on_ac_power fi if [ $? -ne 1 ]; then dbg "run anacron for $host" anacron -q -s -d -n -t /etc/anacrontab-bkp $host.* else dbg "$host not on ac power" fi fi done
Anacron wird verwendet um die Intervalle der Sicherungen zu steuern. Für die Steuerung der Debian Standard /etc/cron.* jobs wurde cron statt anacron konfiguriert, da ja der Backupserver selbst kein anacron benötigt, da er immer läuft. Im Debian-Standard wird dafür anacron verwendet sobald es installiert ist.
$ cat /etc/anacrontab-bkp # /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin HOME=/root LOGNAME=root # days delay job command 1 10 host1.daily backup host1 daily 7 5 host1.weekly backup host1 weekly @monthly 0 host1.monthly backup host1 monthly 1 10 host3.daily backup host3 daily 7 5 host3.weekly backup host3 weekly @monthly 0 host3.monthly backup host3 monthly 1 10 host2.daily backup host2 daily 7 5 host2.weekly backup host2 weekly @monthly 0 host2.monthly backup host2 monthly
$ cat /usr/local/bin/backup #!/bin/bash source lockwait lockfile=/var/run/rsnapshot.pid lockwait $lockfile 300 40 /usr/local/bin/mount-exthdd && /usr/bin/rsnapshot -c /etc/rsnapshot-$1.conf $2 /usr/local/bin/umount-exthdd
Da die Endgeräte üblicherweise tagsüber gesichert werden, wird um den sonstigen Netzwerkverkehr nicht zu beeinträchtigen für rsync ein Bandbreitenlimit abhängig von der typischen Netzwerkverbindung des Gerätes (WLAN, LAN, WAN) gesetzt. Beispiel einer rechnerspezifischen rsnapshot Konfiguration:
$ cat /etc/rsnapshot-host1.conf include_conf /etc/rsnapshot.conf snapshot_root /mnt/exthdd/rsnapshot/host1 exclude /media exclude /mnt backup host1:/ ./ +rsync_long_args=--bwlimit=4166K
4.2.2 Server
Das Backup der Server wird über eine typische, übliche rsnapshot Konfiguration mit cron gesteuert.
$ cat /etc/cron.d/rsnapshot # This is a sample cron file for rsnapshot. # The values used correspond to the examples in /etc/rsnapshot.conf. # There you can also set the backup points and many other things. # # To activate this cron file you have to uncomment the lines below. # Feel free to adapt it to your needs. SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin #m h dom mon dow user command # 0 */4 * * * root /usr/bin/rsnapshot alpha 30 2 * * * root /usr/local/bin/backup server daily 0 2 * * 1 root /usr/local/bin/backup server weekly 30 1 1 * * root /usr/local/bin/backup server monthly
4.2.3 Überwachung
Um zu überpüfen ob und welche Dateien tatsächlich gesichert wurden, ruft ein separater Cron Job wöchentlich find auf um die Dateien zu finden, deren Änderungszeit jünger als 24 h ist. Das Ergebnis wird gemailt:
$ cat /etc/cron.weekly/mailbackupdateien #!/bin/sh /usr/local/bin/mount-exthdd && find /mnt/exthdd/rsnapshot -path '*/daily.0/*' -mtime -1 | /usr/bin/mail -s "Backup Dateien exthdd - 1 Tag alt xy" i@example.com; /usr/local/bin/umount-exthdd
Täglich werden einzelne Dateien geprüft die sich jeden Tag ändern und daher im Backup vorhanden sein müssen:
$ cat /etc/cron.d/check_backups SHELL=/bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin #m h dom mon dow user command 0 8 * * * root /usr/local/bin/mount-exthdd && /usr/local/bin/check_backups ; /usr/local/bin/umount-exthdd
cat /usr/local/bin/check_backups #!/bin/bash BASE=/mnt/exthdd/rsnapshot for SERVER in s1 s2 s3 s4 do check_backup $BASE/server/daily.0/$SERVER/var/log/syslog done for CLIENT in c1 c2 do check_backup $BASE/$CLIENT/daily.0/var/log/syslog done check_backup $BASE/x/daily.0/var/lib/sqlite3/xjournal
cat /usr/local/bin/check_backup #!/usr/bin/python3 import os import time import sys MAX_AGE = 24 # hours def file_age(path:str) -> int: # hours return (time.time() - os.path.getmtime(path)) / 3600 if __name__ == '__main__': try: path = sys.argv[1] except IndexError: sys.stderr.write("Bitte den Pfad der zu prüfenden Datei als ersten Parameter angeben.\n") sys.exit(2) age = file_age(path) if age > MAX_AGE: sys.stderr.write("Datei '%s' ist %.2f h alt. Das ist mehr als das erlaubte Maximum von %sh.\n" % ( path, age, MAX_AGE)) sys.exit(3)