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 2 externe verschlüsselte USB Festplatten. Eine davon ist immer extern physikalisch getrennt verwahrt, während auf die andere laufend vom Server gesichert wird. Wöchentlich werden die Platten getauscht. 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 dem Linux Kernel nicht zuverlässig und mußte deaktiviert werden:
$ cat /etc/modprobe.d/blacklist_uas.conf options usb-storage quirks=0bc2:ab28:u
Die Platten sind mit dm-crypt/luks verschlüsselt und mit ext4 Dateisystem formatiert. Es ist wichtige 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 wenog Ram nicht mehr entschlüsselbar ist. siehe Zwecks Unterscheidbarkeit haben die Festplatten unterschiedliche Gehäusefarben.
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ährend dessen kein Backup möglich ist. Mit 3 Platten gibt es keine Unterbrechungen des Backups wenn eine Platte defekt wird. Die Seagate Platten haben beide leider nicht lange gehalten. Das scheint ein Serienfehler zu sein. Es ist also ratsam verschiedenste Hersteller / Typen für die Platten zu verwenden.
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.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 Konfiguation 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)
Created: 2023-09-20 Mi 13:54