Vor einiger Zeit habe ich für meine Server ein MySQL-Backup-Script geschrieben, welches alle Datenbanken einzeln in verschlüsselte Dateien dumpt und diese per rsync auf einen Server oder in ein anderes Verzeichnis kopiert. Warum eigentlich mit Verschlüsselung wird sich nun der ein oder andere fragen? Nun mein Serveranbieter legt zu meinem Root-Server einen Backup-Space bei, der wahlweise per FTP, Rsync oder Samba erreichbar ist. Da ich einige Features von rsync, wie beispielsweise abgleich eines lokalen Verzeichnisses mit einem entfernten (auch mit Löschen von Dateien, wenn diese am Ausgangsort nicht mehr existieren), schätze, habe ich mich für diesen Weg entschieden. Vielleicht ist dieses Script nicht das eleganteste, aber es funktioniert seit etlichen Monaten bestens und etliche Restores haben auch schon bewiesen, dass es nötig ist.

Zunächst das Script, unten folgen die Erklärungen und Anweisungen zur Benutzung:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/bin/bash
BACKUPPATH="/YOURDIR/";
DELOLDERTHAN=$(date --date '-10 Days' +%s);
MYSQLUSER="YOURLUSER";
MYSQLPASS="YOURPASSWORD";
RSYNCCOMAND="/usr/bin/rsync -qravm --force --delete-after $BACKUPPATH rsync://YOURREMOTESERVER/YOURREMOTEDIR/"
CRYPTPASS="YOURCRYPTPASSWORD";
#########################################################
##############DO NOT CHANGE ANYTHING BELOW###############
#########################################################
TODAY=$(date +%s);
WORKDIR=$BACKUPPATH$TODAY"/";
DBLIST=$WORKDIR"/backup.list";
MD5FILE=$WORKDIR"/backup.md5";
TIMESTAMPFILE=$WORKDIR"/backup.timestamp";

if [ "$1" = "-h" ];then
 echo "Uli's Backup Script V0.5";
 echo "Copyright 2008 by Ulrich Wolf ";
 echo "Parameters:";
 echo "-v Verbose Output with Parameter";
 echo "-f Force Overwrite of Backupdirectory";
 exit 0;
fi
#########################################################
echo "==================================================";
echo -n "Anlegen des Backupverzeichnisses $TODAY";
if ([ -e $WORKDIR ] && [ "$1" != "-f"]); then
 echo "...[fail]";
 if [ "$1" != "-f"]; then
 echo "Directory already exists. Quitting...";
 exit 1;
 fi
fi
mkdir -p $WORKDIR
echo "...[done]";
echo "Backup "$(date '+%F %T') > $TIMESTAMPFILE
mysqlshow -u$MYSQLUSER -p$MYSQLPASS | awk '{print $2}' | sed -e '/^[ ]*$/d' | grep -v Databases | sort >$DBLIST;
DBANZAHL=$(wc -l $DBLIST | cut -d' ' -f 1);
echo "MySQL-Datenbanken werden gesichert - Anzahl: $DBANZAHL";
echo -n "Backup running";
if [ "$1" = "-v" ];then
 for ((i = 0; i < $DBANZAHL; i++)); do
 echo -n '_';
 done;
 echo -n $'_\r';
fi
COUNT=0;
for x in `cat $DBLIST`; do
 mysqldump --opt -u$MYSQLUSER -p$MYSQLPASS $x | gzip -c | /usr/bin/openssl aes-256-cbc -salt -pass pass:$CRYPTPASS > $WORKDIR$x.sql.gz.aes;
 let "COUNT += 1"
 if [ "$1" = "-v" ];then
 echo -n "#";
 sleep 1;
 fi
done;
echo "...[done]";
echo "Backup: $COUNT/$DBANZAHL erfolgreich";
echo -n "MD5:";
md5sum $WORKDIR* >$MD5FILE;
echo "...[done]";
echo "==================================================";
echo "Purging old Backups";
VERZEICHNISSE=$(ls -gGl $BACKUPPATH| grep ^d| tr -s [:blank:] " " |cut -d' ' -f 7);
for dir in $VERZEICHNISSE
do
 if [ $dir -lt $DELOLDERTHAN ];then
 echo "Deleting "$BACKUPPATH$dir;
 rm -R $BACKUPPATH$dir;
 fi;
done
echo "MySQL-Backup abgeschlossen";
echo "==================================================";
echo -n "Executing Rsync";
RSYNC=$($RSYNCCOMAND);
ER=$?;
if [ $? = 0 ] ; then
 echo "...[done]";
else
 echo "...[fail]";
 echo $RSYNC;
fi
echo "==================================================";

Das Script beginnt mit diversen Configs:

  • BACKUPPATH="/YOURDIR/"; Zu Ändern: Konfiguriert das lokale Backupverzeichnis
  • DELODERTHAN=$(date –date ‘-14 Days’ +%s); Für versierte Nutzer: Anzahl der Tage, die ein Backup besteht, bitte nur die Zahl ändern, andere Werte auf eigene Gefahr.
  • MYSQLUSER=“YOURLUSER”; MySQL-Nutzer für den Zugriff auf alle Datenbanken
  • MYSQLPASS=“YOURPASSWORD”; MySQL-Passwort für den Nutzer mit Zugriff auf alle Datenbanken
  • RSYNCCOMAND="/usr/bin/rsync -qravm –force –delete-after $BACKUPPATH rsync://YOURREMOTESERVER/YOURREMOTEDIR/" Rsync-Zielserver
  • CRYPTPASS=“YOURCRYPTPASSWORD”; Verschlüsselungspasswort im Klartext

Sollte das Pruning fehlschlagen, so liegt es an der Zeile:

1
VERZEICHNISSE=$(ls -gGl $BACKUPPATH| grep ^d| tr -s [:blank:] " " |cut -d' ' -f 7);

Evtl muss hinten die Zahl verändert werden. Das Pruning arbeitet bei mir relativ einfach: es werden alle Verzeichnisse untereinander aufgelistet und anschließend wird jede geprüft, ob es veraltet ist. Wenn ja, dann wird es gelöscht und eine entsprechende Meldung ausgegeben.

Natürlich kann man das Script bestens im Cron laufen lassen, ich bekommen täglich zwei Mails dazu und gut is ;)

Restore geht ganz einfach: Die Dateien sind ja nun als *.sql.gz.aes abgelegt. Für den Restore benötigt man nun das Plaintext-SQL-File, welches mit folgendem Befehl zu bekommen ist:

1
openopenssl enc -d -aes-256-cbc -in INPUTFILE -pass pass:YOURCRYPTPASSWORD|gunzip > OUTPUTFILE

Wobei YOURCRYPTPASSWORD durch das oben gesetzte Passwort zu ersetzen ist. INPUTFILE ist das gesicherte Archiv mit der Datenbank und OUTPUTFILE ist das Plaintext-SQL-File.

Bei Fragen einfach melden ;)