Hier mal mein aktuelles Backup-Script mit dem ich aktuell sehr zufrieden
bin. Ich hatte das ganze schon mal
hier angerissen aber
mittlerweile hat sich doch einiges getan. War mein Backup-Script zu
Beginn einfach nur ein Befehl, der täglich mein Home mittels
rsync
über SSH auf meinen Server kopiert und dabei die alte Version
überschrieben hat, so ist das ganze deutlich komplexer und flexibler.
Mittlerweile sichere ich mein /home/, mein /etc/, mein /root/ und
mein /usr/local/. Da mein Backup auf dem Backup-Server auf einer
externen Festplatte gespeichert wird, hänge ich diese vor dem Backup ein
und nach dem Backup aus. Ich habe auch eine Rotation eingebaut um
Snapshots der letzten 7 Tage, sowie monatliche Snapshots des letzten
Jahres zur Verfügung zu stellen. Um nicht unnötig Speicher zu belegen
werden hardlinks genutzt,
da sich große Datenmengen wie die Musiksammlung ja nicht groß ändern.
Das Script liegt unter /etc/cron.daily/ssh_backup
und wird täglich von
anacron
ausgeführt.
Um die Dateirechte zu übertragen benutze ich auf dem Server
sudo, da ich den root-LogIn per
SSH nicht erlaubt habe. Sollte der Backup-Server down sein erhalte ich
eine Email, die ich im Thunderbird
empfange.
Nach langer Rede folgt nun mein Backup-Script:
#! /bin/bash
#### Diese Variablen bitte auf die eigenen Bedürfnisse anpassen
BACKUP_PFADE="/home/martin /etc /root /usr/local"
# Pfade die gesichert werden sollen
ZIELPFAD=/mnt/backup # Pfad auf dem Backupserver (ohne abschließenden /)
ZIEL_EXT=true # true = Wechseldatenträger, false = interner Speicher
ANZAHL_TAGE=7 # Tägliches Backup für x Tage
BENUTZER=martin # Benutzername auf dem Backupserver
SERVER=backup # IP-Adresse oder Hostname des Backupservers
PORT=1418 # SSH-Port des Backupservers
MAC=88:ae:1d:31:cd:17 # MAC-Adresse des Servers für WOL
HISTORY=/root/.backup_hist # Protokoll-Datei
LISTE=/root/installed_packages.txt # Speicherort für Liste der gespeicherten Pakete
#### Don't touch this; domdididom
#### Ab hier bitte nichts anfassen, wenn du nicht sicher weißt was du tust
MONAT=$(date +%-m)
VORMONAT=$(expr $MONAT - 1)
HOST=$(hostname)
# Backup-Server bereit?
if ! ping -c 1 $SERVER > /dev/null
then
# Backup-Server hochfahren
wakeonlan $MAC 1>/dev/null
sleep 60
if ! ping -c 1 $SERVER > /dev/null
then
echo "Backup konnte nicht durchgeführt werden. \nDer Server war nicht erreichbar." | mail -s 'Backup fehlgeschlagen!' $(whoami)@$HOST
exit
fi
fi
# Falls Zieldatenträger Wechselplatte, diese einhängen
if $ZIEL_EXT
then
ssh -p $PORT $BENUTZER\@$SERVER "sudo mount $ZIELPFAD" >/dev/null
# Datei CURRENT zur Protokollierung der aktiven Backups existiert?
if ! ssh -p $PORT $BENUTZER\@$SERVER stat $ZIELPFAD/CURRENT \> /dev/null 2\>\&1
then
ssh -p $PORT $BENUTZER\@$SERVER "touch $ZIELPFAD/CURRENT && echo "0" > $ZIELPFAD/CURRENT"
fi
# CURRENT auslesen und inkrementieren
CURRENT=$(ssh -p $PORT $BENUTZER\@$SERVER "cat $ZIELPFAD/CURRENT")
CURRENT=$(echo "$CURRENT + 1" | bc)
ssh -p $PORT $BENUTZER\@$SERVER "echo $CURRENT > $ZIELPFAD/CURRENT"
fi
# Link 0 -> 12 (für Link auf letztes Backup im Januar) existiert?
if ! ssh -p $PORT $BENUTZER\@$SERVER stat $ZIELPFAD/$HOST/0 \> /dev/null 2\>\&1
then
ssh -p $PORT $BENUTZER\@$SERVER "ln -s $ZIELPFAD/$HOST/12 $ZIELPFAD/$HOST/0"
fi
# Bei Problemen zu Testzwecken auskommentieren
# ssh -v -p $PORT $BENUTZER@$SERVER /bin/true
# Eine Liste der installierten Pakete erstellen
dpkg --get-selections > $LISTE
# Backup per rsync
for PFAD in $BACKUP_PFADE
do
rsync -az --delete --rsync-path='sudo rsync' --rsh="ssh -p $PORT" --link-dest=../$VORMONAT $PFAD $BENUTZER@$SERVER:$ZIELPFAD/$HOST/$MONAT
done
# Erstellen von Snapshots der letzten x Tage
ssh -p $PORT $BENUTZER\@$SERVER "sudo rm -rf $ZIELPFAD/$HOST/daily.$ANZAHL_TAGE"
if [ $ANZAHL_TAGE -gt 1 ]
then
for (( ANZAHL=$ANZAHL_TAGE ; ANZAHL >= 2 ; ANZAHL-- ))
do
ssh -p $PORT $BENUTZER\@$SERVER "sudo mv $ZIELPFAD/$HOST/daily.$(expr $ANZAHL - 1) $ZIELPFAD/$HOST/daily.$ANZAHL"
done
fi
if [ ! $ANZAHL_TAGE -eq 0 ]
then
ssh -p $PORT $BENUTZER\@$SERVER "sudo mv $ZIELPFAD/$HOST/daily.latest $ZIELPFAD/$HOST/daily.1"
ssh -p $PORT $BENUTZER\@$SERVER "sudo cp -al $ZIELPFAD/$HOST/$MONAT $ZIELPFAD/$HOST/daily.latest"
fi
# Falls Zieldatenträger Wechselplatte, diese aushängen sofern kein weiteres Backup aktiv ist (Variable Current)
if $ZIEL_EXT
then
CURRENT=$(ssh -p $PORT $BENUTZER\@$SERVER "cat $ZIELPFAD/CURRENT")
if [ $CURRENT -eq 1 ]
then
ssh -p $PORT $BENUTZER\@$SERVER "echo "0" > $ZIELPFAD/CURRENT"
ssh -p $PORT $BENUTZER\@$SERVER "sudo umount $ZIELPFAD" >/dev/null
else
CURRENT=$(echo "$CURRENT - 1" | bc)
ssh -p $PORT $BENUTZER\@$SERVER "echo "$CURRENT" > $ZIELPFAD/CURRENT"
fi
fi
# Datum und Uhrzeit des Backups protokollieren
date >> $HISTORY
Das Script ist natürlich auf meine Bedürfnisse bzw. Vorlieben zugeschneidert. Aber vielleicht kann es dem ein oder anderen als Inspiration für ein eigenes Backup-Konzept dienen, oder man kann den ein oder anderen Schnippsel für eigene Scripte verwerten.
[Update 2014-10-01]
Da ich mittlerweile zwei Rechner mit Hilfe dieses Scriptes sichere habe
ich nun das Script um eine Funktion erweitert. Erfolgt das Backup auf
ein Wechselmedium wird eine Datei CURRENT
angelegt. Diese wird mit 0
initialisiert und beim Start des Backups inkrementiert. Steht am Ende
des Backups in der Datei eine Zahl > 1
ist noch ein anderes Backup
aktiv und die Zahl in CURRENT
wird dekrementiert und das Wechselmedium
nicht ausgehängt. Steht in CURRENT
eine 1
wird eine 0
zurückgeschrieben und das Laufwerk ausgehängt.
Das ganze ist eine quick and dirty Lösung, da mir erst mal keine
bessere Lösung eingefallen ist. Wenn jemand einen eleganteren Weg kennt
bin ich für Hinweise offen.
Ich habe jetzt ein paar mal die gleichzeitige Durchführung des Backups
an beiden Rechnern forciert und war mit der Funktion zufrieden
(bash -x ...
ist ganz nett um Scriptänderungen zu testen).
[Update 2016-09-24] Ich habe den Ausschnitt aus der /etc/sudoers entfernt, da dieser fehlerhaft war. Mittlerweile lasse ich meinen user per rsync alles ausführen, was nicht wirklich kritisch ist, da der Server eh nicht von außen erreichbar ist.