Einfaches MySQL-Backup mit Pruning und Verschlüsselung mittels bash & rsync

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.

Werbung


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

#!/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 <m [AT] il [DOT] wolf-u [DOT] li>";
        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:

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:

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 😉

Veröffentlicht von

Uli

IT-Nerd und Admin

2 Gedanken zu „Einfaches MySQL-Backup mit Pruning und Verschlüsselung mittels bash & rsync“

  1. Danke für das Script. Leider stellen nur die wenigstens Leute Ihre gebastelten und guten Scripts online, weshalb ich explizit dafür danken möchte.

  2. hi, könntest du mir das Script in soweit abändern, dass der Backup auf FTP-Speicher funktioniert? Hab das mehreremale versucht. Irgendwo liegt ein Denkfehler :-/. Rsync kann einfach nicht richtig mit FTP umgehen.

    danke dir

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.