WordPress-Backup auf dem Server per Cronjob und Shell-Skript
Datenbank und Dateien von WordPress unabhängig von Plugins sichern: ein getestetes Shell-Skript mit WP-CLI, Sperre, Archivprüfung und Aufbewahrung, gestartet per Cronjob, inklusive Restore-Probe.
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Backup-Plugins sind bequem, laufen aber innerhalb von WordPress: Fällt die Website aus, weil ein Update schiefging oder PHP an ein Limit stößt, läuft oft auch das Backup nicht. Haben Sie SSH-Zugriff auf einen eigenen Server oder einen VPS, können Sie die Sicherung unabhängig von WordPress über das Betriebssystem erledigen: ein kurzes Shell-Skript sichert Datenbank und Dateien, ein Cronjob startet es jede Nacht. Diese Anleitung zeigt ein im Labor getestetes Skript mit Sperre gegen Doppelstarts, Prüfung der Archive, Aufbewahrungsregel und Restore-Probe, und erklärt die Stolperstellen, die in der Praxis zu stillen Fehlern führen.
Voraussetzungen
- Linux-Server oder VPS mit SSH-Zugang und
sudo-Rechten, zum Beispiel Debian 13 oder Ubuntu 24.04 - WordPress 7.1 (getestet mit 7.1.2) auf PHP 8.x, Datenbank MariaDB oder MySQL
- WP-CLI (getestet mit 2.12.0) unter
/usr/local/bin/wpund der Datenbank-Client, dermariadb-dumpodermysqldumpmitbringt - Die Werkzeuge
tar,gzip,flockundcron, auf Debian und Ubuntu in der Grundinstallation enthalten - Freier Speicher für mindestens zwei vollständige Sicherungen; im Labor belegte eine frische Installation rund 36 MB je Lauf
- Ein Konto mit der Rolle Administrator in WordPress für die Kontrolle nach dem Restore
Schritt 1: Zielverzeichnis anlegen und Rechte setzen
Die Sicherung enthält wp-config.php mit dem Datenbankpasswort und einen vollständigen Datenbankauszug mit allen Benutzerkonten. Das Zielverzeichnis darf deshalb nur für den Benutzer lesbar sein, der das Backup erstellt. Es liegt außerhalb des Webroots, damit niemand die Archive über den Browser abrufen kann.
Das Skript läuft als der Benutzer, dem die WordPress-Dateien gehören. Auf Debian und Ubuntu mit Apache ist das häufig www-data, bei vielen Hostern ein eigener Systembenutzer. So vermeiden Sie, WP-CLI als root starten zu müssen, was es nur mit --allow-root zulässt.
ls -ld /var/www/html
sudo mkdir -p /var/backups/wordpress
sudo chown www-data:www-data /var/backups/wordpress
sudo chmod 700 /var/backups/wordpressPassen Sie Pfad und Benutzer an Ihre Installation an. Den Eigentümer zeigt die erste Zeile.
Verifizieren: ls -ld /var/backups/wordpress zeigt drwx------ und den Benutzer, dem auch die WordPress-Dateien gehören.
Schritt 2: Backup-Skript anlegen
Legen Sie das Skript unter /usr/local/sbin/wp-backup.sh an, zum Beispiel mit sudo nano /usr/local/sbin/wp-backup.sh:
#!/usr/bin/env bash
# WordPress-Backup: Datenbank und Dateien, mit Aufbewahrung
set -euo pipefail
umask 077
# cron startet mit PATH=/usr/bin:/bin, wp liegt meist in /usr/local/bin
export PATH="/usr/local/bin:/usr/bin:/bin"
WP_PATH="/var/www/html"
ZIEL="/var/backups/wordpress"
BEHALTEN_TAGE=14
STAMP="$(date +%F_%H%M%S)"
DB="$ZIEL/db_$STAMP.sql.gz"
FILES="$ZIEL/files_$STAMP.tar.gz"
exec 9>"$ZIEL/.lock"
flock -n 9 || { echo "Backup läuft bereits, Abbruch." >&2; exit 1; }
# Bei Abbruch halbfertige Dateien entfernen
trap 'rm -f "$DB.part" "$FILES.part"' EXIT
# 1. Datenbank (Zugangsdaten liest WP-CLI aus wp-config.php)
wp --path="$WP_PATH" db export - --single-transaction | gzip > "$DB.part"
# 2. Dateien ohne Cache und temporären Update-Ordner
tar -czf "$FILES.part" -C "$WP_PATH" \
--exclude=./wp-content/cache --exclude=./wp-content/upgrade .
# 3. Archive prüfen, erst dann umbenennen
gzip -t "$DB.part"
tar -tzf "$FILES.part" > /dev/null
mv "$DB.part" "$DB"
mv "$FILES.part" "$FILES"
# 4. Sicherungen älter als BEHALTEN_TAGE löschen
find "$ZIEL" -maxdepth 1 -type f \( -name "db_*.sql.gz" -o -name "files_*.tar.gz" \) \
-mtime +"$BEHALTEN_TAGE" -delete
echo "Backup $STAMP fertig: $(du -ch "$DB" "$FILES" | tail -1 | cut -f1)"Die wichtigsten Entscheidungen im Skript:
set -euo pipefailbricht beim ersten Fehler ab, auch wenn der Fehler in einer Pipe auftritt. Ohnepipefailwürde ein Datenbankfehler hinter| gzipverschwinden.umask 077sorgt dafür, dass neue Dateien nur für den Eigentümer lesbar sind.flock -nverhindert Doppelstarts, etwa wenn ein Lauf wegen großer Mediendateien länger dauert als geplant.- Die Archive entstehen zunächst als
.part-Datei und bekommen erst nach bestandener Prüfung ihren endgültigen Namen. Dertraplöscht Reste, wenn das Skript abbricht. So finden Sie im Zielordner nur vollständige Sicherungen. --single-transactionreicht WP-CLI anmariadb-dumpbzw.mysqldumpdurch. Bei InnoDB-Tabellen, dem Standard in aktuellen WordPress-Installationen, entsteht so ein konsistenter Stand, ohne die Website zu sperren.- Ausgeschlossen sind
wp-content/cacheundwp-content/upgrade, weil sich beide Ordner neu erzeugen lassen. Weitere Ausschlüsse, etwa Backup-Ordner von Plugins, ergänzen Sie mit zusätzlichen--exclude-Angaben.
Machen Sie das Skript ausführbar und prüfen Sie die Syntax:
sudo chmod 755 /usr/local/sbin/wp-backup.sh
bash -n /usr/local/sbin/wp-backup.sh && echo "Syntax ok"Verifizieren: bash -n gibt keine Fehlermeldung aus, und ls -l /usr/local/sbin/wp-backup.sh zeigt -rwxr-xr-x.
Schritt 3: Skript von Hand testen
Starten Sie das Skript einmal manuell als der Benutzer, unter dem später auch der Cronjob läuft:
sudo -u www-data /usr/local/sbin/wp-backup.sh
ls -la /var/backups/wordpressIm Labor lautete die Ausgabe „Backup 2026-09-30_190658 fertig: 36M“. Im Zielordner lagen danach db_…sql.gz und files_…tar.gz, beide mit den Rechten -rw-------. Prüfen Sie stichprobenhaft den Inhalt:
zcat /var/backups/wordpress/db_*.sql.gz | head -3
tar -tzf /var/backups/wordpress/files_*.tar.gz | grep wp-config.phpDie erste Zeile des Dumps beginnt bei MariaDB 11.8 mit einem Kommentar zum Sandbox-Modus, danach folgt „MariaDB dump“ mit Versionsnummer. Im Dateiarchiv muss ./wp-config.php auftauchen.
Testen Sie auch den Fehlerfall. Im Labor führte ein falscher WP_PATH zu „Error: This does not seem to be a WordPress installation.“ und Rückgabewert 1; im Zielordner blieb keine halbe Datei zurück. Ein zweiter Start während eines laufenden Backups endete mit „Backup läuft bereits, Abbruch.“
Verifizieren: echo $? direkt nach dem Lauf gibt 0 aus, und beide Archive sind größer als wenige Kilobyte. Ein Datenbank-Dump mit 20 Byte ist ein leeres gzip-Archiv und deutet auf einen Fehler hin.
Schritt 4: Cronjob einrichten
Öffnen Sie die Crontab des Backup-Benutzers:
sudo crontab -u www-data -eund tragen Sie eine Zeile für den nächtlichen Lauf ein, hier täglich um 2:30 Uhr:
30 2 * * * /usr/local/sbin/wp-backup.sh >> /var/backups/wordpress/backup.log 2>&1Das Protokoll landet im Zielordner, weil der Benutzer www-data dort schreiben darf, unter /var/log in der Regel nicht. Die Grundlagen der Zeitangaben erklärt die Anleitung Cron und crontab richtig nutzen.
Cron startet Befehle mit einer sehr knappen Umgebung. Im Labor zeigte der erste Cron-Lauf ohne die PATH-Zeile im Skript „wp-backup.sh: line 20: wp: command not found“, obwohl derselbe Aufruf in der SSH-Sitzung funktionierte. Deshalb setzt das Skript den PATH selbst. Dasselbe gilt für Umgebungsvariablen: Liest Ihre wp-config.php Zugangsdaten aus der Umgebung, wie es etwa das offizielle Docker-Image tut, fehlen sie im Cron-Lauf. Im Labor endete das mit „mariadb-dump: Got error: 2005: "Unknown server host 'mysql'"“. Tragen Sie solche Variablen dann oben in die Crontab ein.
Zum Testen setzen Sie die Zeit vorübergehend auf die nächste Minute, warten den Lauf ab und stellen danach auf den endgültigen Zeitpunkt zurück.
Verifizieren: sudo crontab -u www-data -l zeigt die Zeile, und nach dem ersten Lauf steht in backup.log „Backup … fertig“ ohne Fehlermeldung davor.
Schritt 5: Sicherungen vom Server wegkopieren
Ein Backup auf demselben Server schützt vor Bedienfehlern und fehlgeschlagenen Updates, nicht aber vor einem Plattendefekt, einer Kündigung durch den Anbieter oder einem Angreifer mit Root-Rechten. Kopieren Sie die Archive deshalb zusätzlich auf einen zweiten Speicherort: ein NAS im Büro, einen Speicherdienst mit S3-Schnittstelle oder einen zweiten Server. Wie Sie das mit rclone oder restic umsetzen, zeigen die Anleitungen 3-2-1-Backup-Strategie umsetzen und Datenbank-Backups mit cron automatisieren.
Die Aufbewahrung im Skript bezieht sich nur auf den lokalen Ordner. Am externen Ziel brauchen Sie eine eigene Regel, sonst wächst der Speicher unbegrenzt oder die Kopien verschwinden zu früh.
Spätestens an dieser Stelle zeigt sich, dass ein Backup kein einmaliges Projekt ist: Speicherplatz, Log und externe Kopie wollen regelmäßig kontrolliert werden, dazu kommen die Updates. Wer diese Aufgaben nicht selbst im Kalender halten möchte, kann sie abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt wöchentliche Backups auf externen Speicher mit vier Wochen Aufbewahrung sowie Updates von WordPress, Plugins und Themes.
Verifizieren: Die jüngste Sicherung liegt mit gleicher Dateigröße auch am externen Ziel.
Schritt 6: Wiederherstellung proben
Ein Backup gilt erst als funktionierend, wenn Sie daraus wiederhergestellt haben. Proben Sie das auf einer Testinstanz, nicht auf der Live-Website, denn der Import überschreibt die Datenbank vollständig.
mkdir -p /tmp/restore && cd /tmp/restore
tar -xzf /var/backups/wordpress/files_DATUM.tar.gz
gunzip -c /var/backups/wordpress/db_DATUM.sql.gz | wp --path=/pfad/zur/testinstanz db import -Im Labor wurde nach dem Backup ein zusätzlicher Beitrag „NachBackup“ angelegt. Nach dem Import meldete WP-CLI „Success: Imported from 'STDIN'.“, und wp post list zeigte nur noch den Stand zum Zeitpunkt der Sicherung. Genau das erwarten Sie: Alles, was nach dem Backup entstand, ist nach einer Wiederherstellung verloren. Daraus leitet sich der sinnvolle Abstand der Sicherungen ab.
Liegt die Testinstanz unter einer anderen Adresse, passen Sie die URLs danach mit wp search-replace an, niemals per SQL-Ersetzung, weil WordPress Einstellungen serialisiert speichert. Eine feste Routine für solche Proben beschreibt die Anleitung Backup-Restore-Test als feste Routine etablieren.
Verifizieren: Die Testinstanz startet, Sie können sich anmelden, und der jüngste Beitrag entspricht dem Stand zum Zeitpunkt der Sicherung.
Typische Fehler
| Meldung oder Symptom | Ursache | Lösung |
|---|---|---|
| „wp: command not found“ nur im Cron-Lauf | Cron nutzt einen knappen PATH | export PATH=… im Skript oder vollen Pfad zu wp |
| „Got error: 2005: "Unknown server host …"“ | Datenbankzugang kommt aus Umgebungsvariablen, die Cron nicht kennt | Variablen oben in die Crontab eintragen |
| „Error: This does not seem to be a WordPress installation.“ | Falscher WP_PATH | Pfad zum Ordner mit wp-config.php eintragen |
| „Backup läuft bereits, Abbruch.“ | Vorheriger Lauf noch aktiv | Laufzeit prüfen, Cron-Zeitpunkt verschieben |
| Datenbankarchiv nur 20 Byte groß | Export ist gescheitert, leeres gzip | Skript mit set -o pipefail nutzen, Log lesen |
| Keine Log-Datei, Cron scheint nicht zu laufen | Log-Pfad nicht beschreibbar, etwa unter /var/log | Log in den Backup-Ordner schreiben |
Übrig gebliebene .part-Dateien | Prozess wurde hart beendet, der trap lief nicht | Dateien löschen, Ursache (Speicher, Neustart) klären |
Häufige Fragen
Reicht der Snapshot meines Hosters nicht aus?
Ein Snapshot des ganzen Servers ist eine sinnvolle Ergänzung, liegt aber meist beim selben Anbieter und lässt sich oft nur komplett zurückspielen. Das Skript liefert einzelne Archive, aus denen Sie gezielt nur die Datenbank oder einzelne Dateien holen können.
Wie oft sollte das Backup laufen?
So oft, wie Sie Datenverlust hinnehmen können. Für eine Website, die sich wöchentlich ändert, genügt ein nächtlicher Lauf. Bei einem Shop mit täglichen Bestellungen sichern Sie die Datenbank häufiger, etwa alle paar Stunden mit einem zweiten Cronjob nur für den Datenbankteil.
Funktioniert das auch auf Shared Hosting?
Nur, wenn der Hoster SSH, WP-CLI und eigene Cronjobs erlaubt. Viele Hoster bieten Cronjobs im Kundenmenü an; der Befehl bleibt derselbe, die Pfade nennt der Hoster.
Testumfang
Wir haben die Sicherung in einer lokalen Testumgebung mit WordPress 7.1.2 manuell als www-data laufen lassen und die Datenbank danach wieder eingespielt und kontrolliert. Den Cron-Lauf haben wir einmal mit und einmal ohne PATH-Zeile geprüft.
Die Übertragung auf externe Ziele und sehr große Installationen haben wir nicht getestet. Probieren Sie das Verfahren in solchen Fällen zuerst an einer Kopie aus.
Fazit
Ein Shell-Skript mit Cronjob sichert WordPress unabhängig vom Zustand der Website und lässt sich vollständig nachvollziehen. Entscheidend sind die Details: Abbruch bei Fehlern, geprüfte Archive, ein eigener PATH für Cron, eine Kopie außerhalb des Servers und eine geprobte Wiederherstellung. Wenn Sie Backups und Updates lieber in feste Hände geben, übernimmt das die WordPress-Wartung von Marcel Schönfelder.


