How To: Daten-Backup eines Webhostings unter Linux

Wer einen eigenen Webserver betreibt, sei es privat oder geschäftlich, sollte sich auf jeden Fall mit dem Thema Daten-Backups beschäftigen. Es kann immer mal passieren, dass Daten verloren gehen. Ob nun ein Hackerangriff Daten zerstört hat, die Anwendung nach einem Update nicht mehr lauffähig ist oder man selbst aus Versehen Dateien gelöscht hat, wenn in so einer Situation ein Backup existiert, erspart man sich viel Zeit und Nerven. Aber wie sichert man die Daten auf einem Webserver am einfachsten? Das hier beschriebene Vorgehen verwendet größtenteils einfache Linux-Boardmittel und benötigt zur Einrichtung lediglich ein Root-Zugang zum Server.

Zu Beginn muss ich ein wenig ausholen, denn bevor man ein automatisiertes Verfahren einrichten kann, muss erstmal die Struktur der Hosts eingerichtet werden. Wer mehrere Webseiten auf seinem Server bereitstellt, braucht einen einheitlichen Aufbau der einzelnen Hosts. Eine saubere Architektur vereinfacht nicht nur die Wartung, sondern lässt auch automatisierte Backups zu.
Die Hosts auf meinem privaten Webserver sind beispielsweise nach dem folgendem Schema aufgebaut:

  • /var/www/virtual/seite.de/
    Das Root-Verzeichnis für einen einzelnen Host
  • /var/www/virtual/seite.de/htdocs
    In diesem Verzeichnis liegen die ausführbaren HTML- und PHP-Dateien
  • /var/www/virtual/seite.de/logs
    Error- und Zugriffslog von Apache
  • /var/www/virtual/seite.de/backups
    Hier werden später die Backups abgelegt
  • /var/www/virtual/seite.de/subdomains/test/htdocs
    Hier lassen sich Subdomains mit einem eigenen Datenverzeichnis anlegen

Jeder Host bekommt dann noch eine eigene Datenbank. In diesem Beispiel wäre der Name der Datenbank seite.de.
Ein solcher Aufbau ist nicht zwingend notwendig, macht es aber später einfacher neue Hosts anzulegen und dabei auch den Backup-Mechanismus zu aktivieren.

Jetzt aber genug zum Aufbau der Hosts. Als nächstes sollte man sich überlegen welche Daten gesichert werden sollen. Ich empfehle ein Backup der Datenbank und Anwendungsdaten (htdocs). Mit diesen Daten lässt sich eine Website relativ schnell auf ein anderes System transferieren.

Bevor wir anfangen, melden wir uns aber erstmal als Root-Benutzer bei der Server-Konsole an (z.B. mit SSH).

1. MySQL-Datenbank sichern

Als erstes erstellen wir ein Shell/Bash-Skript (z.B. nano /usr/backup-mysql.sh) zum exportieren der kompletten Datebank mit folgendem Inhalt:

#!/bin/sh
mysqldump -uXUserX -pXPasswordX $1 | gzip > /var/www/virtual/$1/backups/mysql_`date +%d-%m-%Y`.sql.gz

Das XUserX und XPasswordX bitte durch korrekte Zugangsdaten der Datenbank ersetzen.
Beim späteren Aufruf des Shell-Skripts wird die Datenbank einer bestimmten Website gzip-komprimiert in das dazugehörige Backup-Verzeichnis gelegt und der Name mit dem aktuellem Datum versehen.

2. FTP-Daten sichern

Anschließend wird ein zweites Shell/Bash-Skript erstellt (z.B. vim /usr/ftp-backup.sh, das die kompletten FTP-Daten speichert:

#!/bin/sh
tar cfvz /var/www/virtual/$1/backups/ftp_`date +%d-%m-%Y`.tar.gz /var/www/virtual/$1/htdocs/*

Hier müsste ggf. der Pfad angepasst werden. Das $1 ist als Platzhalter für den Namen des Hosts gedacht, der später bei Ausführung des Skripts als Parameter übergeben wird.
Auch hier wird wieder das komplette htdocs-Verzeichnis gzip-komprimiert und mit dem aktuellem Datum im Namen in das Backup-Verzeichnis gelegt.

3. Backup extern sichern (optional)

Wer auf Nummer sicher gehen möchte, kopiert das letzte Backup nochmal extern auf einem anderen Server. Dazu habe ich ein Python-Skript geschrieben, das die Daten per SFTP auf meinem Backup-Space überträgt:

View Code PYTHON
#!/usr/bin/python
 
import os, glob, paramiko, sys
 
host = "xxx.domain.com"
port = 22
username = "XXX"
password = "XXX"
 
localPath = "/var/www/virtual/" + sys.argv[1] + "/backups/"
remotePath = "/mnt/array1/share/server-backups/" + sys.argv[1] + "/"
 
def getLastBackupFile(path, type):
        files = filter(os.path.isfile, glob.glob(path + type + "_*"))
        files.sort(key=lambda x: os.path.getctime(x))
        return files[len(files)-1]
 
transport = paramiko.Transport((host, port))
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
 
localPathMysql = getLastBackupFile(localPath, "mysql")
remotePathMysql = remotePath + os.path.basename(localPathMysql)
print "Copying " + localPathMysql + " to " + username + "@" + host + ":" + remotePathMysql
sftp.put(localPathMysql, remotePathMysql)
 
localPathFtp = getLastBackupFile(localPath, "ftp")
remotePathFtp = remotePath + os.path.basename(localPathFtp)
print "Copying " + localPathFtp + " to " + username + "@" + host + ":" + remotePathFtp
sftp.put(localPathFtp, remotePathFtp)
 
sftp.close()
transport.close()

Das Ganze speichern wir ab unter backup-sftp.py, aber zuvor müssen natürlich die Zugangsdaten aus den Zeilen 5 – 8 eingetragen werden.

4. Cronjob anlegen

Damit die oben beschriebene Shell- und Python-Skripts überhaupt ausgeführt werden, müssen jetzt noch Cronjobs angelegt werden. Mit dem Befehl crontab -e öffnet sich ein Text-Editor, in dem die Backup-Cronjobs nach folgendem Schema angelegt werden können:

## MySQL Backups
# seite.de - jeden Montag abend um 18:00 Uhr
0 18 * * 1 /bin/sh /usr/backup-mysql.sh seite.de > /dev/null 2>&1
 
## FTP Backups
# seite.de - jeden ersten Tag im Monat um 01:00 Uhr
0 1 1 * 0 /bin/sh /usr/ftp-backup.sh seite.de > /dev/null 2>&1
 
## Remote Backups
# seite.de - jeden zweiten Tag im Monat um 08:00 Uhr
0 8 2 * * /usr/bin/python /usr/scripts/backup-sftp.py seite.de > /dev/null 2>&1

Der erste Befehl führt das MySQL-Shell-Skript aus und übergibt hier nur den Namen der Datenbank/Host (seite.de), die gesichert werden soll.
Der zweite Befehl führt das FTP-Shell-Skript aus, bei dem das htdocs-Verzeichnis des Host gesichert wird. Auch hier wird lediglich der Name des Hosts übergeben und das Skript findet den Pfad automatisch.
Jetzt zeigt sich auch warum ein einheitlicher Aufbau der Hosts so wichtig ist. Die Skripte lassen sich für jeden Host problemlos wiederverwenden und sind dadurch auch für neue Hosts einfach zu erweitern.

Damit wären alle Websites auf unserem Server gesichert und das ausschließlich mit Linux-Boardmitteln (mal abgesehen von Python, das aber meistens schon vorinstalliert ist). Der Konfigurationsaufwand hält sich – wenn man sich an einen einheitlichen Aufbau der Hosts gehalten hat – auch in Grenzen.

Schreibe einen Kommentar

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