All-in-One Backup-Skript für all-inkl.com

Nach der erfolgreichen Migration meiner Webseiten zu all-inkl.com stellte ich fest, dass eine automatisierte Sicherungsoption fehlte. Die verfügbaren Lösungen im Internet erfüllten nicht meine Anforderungen, weshalb ich beschloss, ein eigenes Backup-Skript in PHP zu entwickeln.

Über das Skript

Das resultierende Skript sichert alle Seiten und Datenbanken, die auf all-inkl.com gehostet sind, und bietet zusätzliche Komfortfunktionen, die in anderen Skripten fehlen.

Funktionen des Skripts

  • Manuelle oder automatisierte Ausführung: Das Skript kann entweder manuell durch Aufrufen einer URL oder automatisiert über einen Cron-Job ausgeführt werden.
  • Benachrichtigungen: Nach jeder Sicherung informiert das Skript über die gesicherten Datenmengen und den Füllzustand des Sicherungsordners. Die Benachrichtigungseinstellungen sind konfigurierbar, so dass z.B. nur bei Fehlern benachrichtigt wird.
  • Archivierungsoptionen: Es kann zwischen schneller (gzip) oder kleiner (bzip2) Archivierung gewählt werden.
  • Quotenverwaltung: Im Skript kann eine Quota für den maximal zu nutzenden Speicher für Backups festgelegt werden. Überschreitet die Sicherung diese Grenze, werden ältere Dateien gelöscht.
  • FTP-Unterstützung: Das Skript kann die Daten an einen FTP-Server senden, entweder über SSL oder unverschlüsselt.

Konfiguration im Skript

Das vollständige Skript steht zum Download bereit (weiter unten). Hier sind einige wichtige Einstellungsbereiche:

// ########## START EDITING HERE ##########

// script settings
// -----------------------------------------------------------------------------
// use appropriate amount of memory and execution time. allowed values depend on
// your hoster (in this case probably all-inkl.com) and package.
$config["php"]["max_execution_time"] = 600; // seconds
$config["php"]["memory_limit"] = "256M"; // megabytes

// general backup settings
// -----------------------------------------------------------------------------
// the target directory is relative to the root of the webspace and has to be
// entered without a trailing slash (e.g. "backup" results in
// /www/htdocs/w0123456/backup). make sure to store nothing else in here because
// old files will be deleted as soon as the quota is met!
$config["backup"]["enabled"] = true; // only disable for testing purposes
$config["backup"]["cleanup"] = true; // disable to never remove any backups
$config["backup"]["target_directory"] = "backup";
$config["backup"]["quota"] = 100 * 1024**3; // in bytes
$config["backup"]["compression_algorithm"] = "gz"; // "gz" = fast, "bz2" = small

// mail settings
// -----------------------------------------------------------------------------
$config["mail"]["enabled"] = true;
$config["mail"]["errors_only"] = false;
$config["mail"]["from"] = "mail@your-domain.com";
$config["mail"]["to"] = "mail@your-domain.com";
$config["mail"]["subject"] = "Backup complete";

// ftp settings
// -----------------------------------------------------------------------------
$config["ftp"]["enabled"] = false;
$config["ftp"]["unsecure_fallback"] = true; // warning! files can be sent unencrypted
$config["ftp"]["host"] = "ftp.example.com";
$config["ftp"]["port"] = "21";
$config["ftp"]["user"] = "user";
$config["ftp"]["pass"] = "password";
$config["ftp"]["dir"] = "/backups"; // must exist on the server

// locale settings
$config["locale"]["timestamp_format"] = "Y-m-d_H-i-s";
$config["locale"]["date_format"] = "Y-m-d";
$config["locale"]["filename_timestamp_format"] = "Y-m-d";

// sites settings
// -----------------------------------------------------------------------------
// a site is a set of folders and databases that should be archived together.
// to declare multiple sites just copy the settings block like this:
// $sites[] = [...data of site 1...];
// $sites[] = [...data of site 2...];
// - description: a short summary of the site (e.g. "dummy.com main page").
//   used for logging purposes.
// - backup_prefix: backup files will use this as a prefix. be sure to include
//   only characters a-z, A-Z, 0-9
//   and underscores here to be on the safe side.
// - folders: an array of all folders that belong to the site (subfolders are
//   included automatically).
//   folders are relative to the ftp root directory.
// - databases: an array of all databases that belong to the site.
//   - db: database name.
//   - user: username. for all-inkl.com this equals the database name.
//   - pass: password for the database.
$sites[] = [
	"description" => "your-domain.com WordPress",
	"backup_prefix" => "your_domain_de",
	"folders" => [ 
		"your-domain.de/www"
	],
	"databases" => [
		[ "db" => "d0123456", "user" => "d0123456", "pass" => "password123" ]
	]
];

// ########## STOP EDITING HERE (unless you know what you're doing) ##########

Die Optionen sind weitgehend selbsterklärend oder im Skript kommentiert. Bitte passt vor der Ausführung insbesondere die E-Mail-Adresse an.

Hinweise zur Konfiguration

  • Das Zielverzeichnis wird relativ zum Hauptverzeichnis (/www/htdocs/w0123456/) festgelegt und muss bereits existieren. Es muss daher manuell über FTP erstellt werden.
  • Im Skript wird das Konzept von „Sites“ verwendet, um zusammengehörige Ordner und Datenbanken zu organisieren. Eine „Site“ kann mehrere solcher Elemente enthalten, die gemeinsam gesichert werden. Alle Ordner einer Site werden in ein einziges Archiv komprimiert, während jede Datenbank in einem separaten Archiv gesichert wird. Jede Site verfügt über eine Beschreibung, wie zum Beispiel „phenx.de WordPress“, und einen Präfix, der den Sicherungsdateien vorangestellt wird, wie „phenx_de“.
  • Um mehrere Sites zu definieren, kann der Bereich $sites[] = [ ... ] im Skript mehrfach wiederholt werden. Für diejenigen, die nicht mit PHP vertraut sind oder üblicherweise mit weniger kuriosen Programmiersprachen arbeiten: Diese Syntax fügt dem Array am Ende einen neuen Eintrag hinzu.

Einrichtung

Die korrekt konfigurierte Datei backup.php muss nun auf all-inkl.com übertragen werden, um dort täglich ausgeführt zu werden. Die folgenden Schritte erläutern den Prozess.

1. Subdomain erstellen: Zunächst erstellen wir eine neue Subdomain. In diesem Beispiel verwende ich „backup.phenx.de“ (Hinweis: Diese Subdomain wird nicht produktiv genutzt).

2. Backup-Verzeichnis anlegen: Im neu erstellten Verzeichnis legen wir mit einem FTP-Client ein weiteres Verzeichnis namens „backup“ an. Dies ist notwendig, um die Subdomain mit SSL zu schützen, da Let’s Encrypt nicht zugreifen kann, wenn der Hauptordner geschützt ist.

3. Verzeichnisschutz einrichten: Als nächstes schützen wir das neue Verzeichnis mit einem Benutzernamen und Passwort. Diese Anmeldedaten werden später für den Cron-Job benötigt, um das Skript aufzurufen. Auch ein manueller Aufruf über den Browser funktioniert mit diesen Anmeldedaten.

4. Cron-Job einrichten: Je nach Bedarf legen wir einen Cron-Job an, zum Beispiel für eine tägliche Ausführung. Die URL muss auf das cron_backup.php Skript verweisen. Eine E-Mail-Adresse ist nicht erforderlich, da das Skript die Benachrichtigungen selbst verwaltet.

5. SSL-Zertifikat aktivieren: Wir schützen die Seite nun mit einem Let’s Encrypt SSL-Zertifikat. Dazu gehen wir auf die „bearbeiten“ Seite der Subdomain und dann auf „SSL-Schutz“ – bearbeiten. Nach Bestätigung der AGBs ist der Schutz aktiv.

6. HTTP auf HTTPS umleiten und HSTS aktivieren: Optional können wir die Umleitung von HTTP auf HTTPS aktivieren und HSTS einschalten, um die Sicherheit zu erhöhen.

7. Backupskripte platzieren: Zum Abschluss legen wir die Backupskripte in das passwortgeschützte Verzeichnis (erkennbar an den Dateien .htaccess und .htpasswd).

8. Manueller Aufruf des Skripts: Nun können wir das Skript manuell aufrufen, in meinem Beispiel unter https://backup.phenx.de/backup/backup.php. Bei der Eingabeaufforderung geben wir die zuvor festgelegten Benutzerdaten ein.

Das Ergebnis wird sowohl im Browser als auch per E-Mail angezeigt (Screenshots nach Hinzufügen weiterer Seiten).

Download

Die neueste Version des Skriptes findet ihr auf Github unter webhost_backup. Zum Herunterladen geht einfach zu „Code“ und wählt „Download ZIP“.

Falls ihr zur Entwicklung beitragen möchtet, könnt ihr gerne Issues oder Pull Requests auf Github erstellen. Ich sehe das dann direkt dort.

Wenn diese Seite für dich hilfreich war und du dich bei mir bedanken möchtest, dann freue ich mich ganz außerordentlich darüber, wenn du für deinen nächsten Einkauf bei amazon.de über diesen Link gehst. Ich bekomme dann eine kleine Provision, für dich kostet es keinen Cent extra. Wenn du mich lieber anders unterstützen möchtest, findest du hier hier weitere Möglichkeiten.

21 Kommentare zu „All-in-One Backup-Skript für all-inkl.com“

  1. Hallo Eiko,
    tolles Skript, vielen Dank dafür!
    Gibt es eine Möglichkeit, auch einzelne Dateien mit ins Backup zu nehmen? Ggf. als
    „files“ => [ „path/to/composer.json“ ]
    im $sites-Array?

    1. Das lässt sich recht einfach erweitern. Wenn du die Angaben so pflegst wie du schreibst kannst du weiter unten dann einfach den ganzen Block „foreach ($site[„folders“] as $folder)“ in „foreach ($site[„files“] as $folder)“ umbenennen und dann in der Schleife den Code anpassen, so dass er nur noch eine einzelne Datei erwartet. Dürften nur ein paar Zeilen sein, die da anzupassen sind. Sag bescheid, wenn dabei Probleme aufkommen, dann schaue ich mir das nochmal an.

      1. Danke, das hat funktioniert – Einzeldateien lassen sich nun auch sichern!
        Wenn du das Skript hier entsprechend aktualisieren möchtest, schicke ich es dir gerne zu.

          1. Hallo zusammen,

            super Skript, vielen Dank!
            Schade das die Funktion nicht von All-Inkl selbst angeboten wird.

            Version 1.0 hat ohne Probleme funktioniert.
            Version 1.1 hatte leider nen kleinen Fehler denke ich, in Zeile 235 fehlt das schließen der „foreach ($site[„files“] as $file) {
            “ mit „}“ – sonst startet das Backup leider nicht.

            Ich würde derartige Fixes auch gern selbst beisteuern. Daher die Frage, schon mal überlegt das Skript auf GitHub zur Verfügung zu stellen und PRs zu akzeptieren?

            Beste Grüße,
            Christian

  2. Hallo, vielen Dank für das Super-Script. Es hat auf Anhieb bei mir funktioniert. Deine Anleitung ist auch super ausführlich und klärt alle Fragen, sodass ich es ohne Probleme einrichten konnte. Tolle Arbeit und Danke, dass du es mit allen teilst.

    1. Hallo Peter, danke für den Beitrag. Die „important-file.ext“ ist einfach nur ein Beispiel, wie man eine zusätzliche einzelne Datei in das Backup einschließen kann. Wenn es nicht benötigt wird, kann das Array einfach leer gelassen werden ("files" => [],).

  3. Hallo Eiko,

    ich nutze aktuell das Script von Christian Schurig, das es in verschiedenen „Ausbaustufen“ gibt. Das „größte“ Script bietet automatisierte Sicherung von FTP und SQL –UND– den gleichzeitigen Export per FTP auf einen anderen Server. Letzteres leider nur theoretisch, denn entweder ist ein Fehler im Script oder es hat sich im Laufe der Jahre ein Befehl geändert, jedenfalls funktioniert gerade der Export nicht. Es kann keine Verbindung zum jeweiligen Server aufgebaut werden. Mehrfach versucht mit verschiedenen Zielen: Hetzner Store Box, Strato HiDrive, Netcup Webhosting… in allen Fällen scheitert mit dem Script der FTP-Export.

    Leider ist Christian Schurig nicht kontaktierbar. Seine Website hat weder ein Impressum noch irgendeine Kontaktmöglichkeit. Weshalb ich auch nicht ihn als Ersteller des Scripts befragen kann.

    Deshalb meine Frage an dich: kannst du in dein Script auch den automatischen FTP-Export zu einem anderen Server einbauen? Oder kennst du das Script von Christian Schurig und kannst mir evtl. weiterhelfen, weshalb es mit diesem nicht (mehr?) klappt? Respektive ist dieses Script hier zu finden: https://it-stack.de/09/06/2015/backup-loesung-fuer-ftp-und-mysql-in-php/

    Denn die Sicherung von FTP und SQL auf den identischen Server ist zwar besser als gar keine Sicherung und ausreichend für den Fall, dass man selbst manuell irgendwas zerschossen hat, aber falls der Fall der Fälle eintritt und was mit dem Server selbst ist, nutzen einem die auf selbigem liegenden Backups halt herzlich wenig.

    Gruß
    Marcus

    1. Hallo Marcus,

      ich kenne das Skript nicht im Detail. Habe allerdings einmal kurz reingeschaut eben und es wirkt als hätte Christian ein sehr ordentliches Logging eingebaut. Damit müsste die genaue Stelle des Fehlschlagens doch eingentlich angezeigt werden?

      Was ich mir vorstellen könnte ist z.B. dass der Regex Befehl, der den FTP Connection String auseinandernimmt mit komplexen Passwörtern nicht klar kommt, aber das ist nur eine reine Spekulation auf den ersten Blick.

      Gruß Eiko

  4. Hallo Eiko,

    danke für die Antwort. Leider wird keine konkrete Fehlermeldung ausgegeben. Deshalb bin ich ja so verwirrt um nicht zu sagen verzweifelt. Käme eine konkrete Meldung mit „Fehler in Zeile XY“ ließe es sich ja eingrenzen und lokalisieren. Aber ich erhalte nur den Hinweis „Fehler beim Verbinden mit dem FTP Server …“ wie in Zeile 291 des Scriptes zu finden. Aber aus welchem Grund es zu dieser Fehlermeldung kommt, kann ich leider nicht nachvollziehen, dafür sind meine PHP-Kenntnisse wiederum zu gering.

    Was aber meinst du oder verstehst du unter „komplexe Passwörter“? Respektive was wären Kriterien für ein „nicht komplexes Passwort“? Maximale Zeichenanzahl? Bestimmte Zeichen die nicht enthalten sein dürfen?

    1. Im Wesentlichen darf kein „@“ im Passwort enthalten sein bei dem Regex das er verwendet. Gibt das Skript denn gar keine weiteren Meldungen aus? Das erscheint mir vom Code her eigentlich sehr untwahrscheinlich.. vor dem „Fehler beim Verbinden mit dem FTP Server“ kommen eigentlich noch diverse andere echo Ausgaben, egal ob es gut geht oder nicht.

  5. Sehr geil Eiko,
    bin schon seit Tagen auf der Suche und dein Script ist quasi maßgeschneidert 🙂
    Mein Backup wäre ca.14 Gb groß, würde über FTP trotzdem raus gehen?
    Gruß
    Niko

Kommentar verfassen

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

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.