Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung WordPress 30.09.2026 · 9 min Lesezeit

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

Grafik mit der Überschrift Server-Backup per Cronjob, drei Karten Cronjob, Skript, Sicherung und einem stilisierten WordPress-Adminbereich

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/wp und der Datenbank-Client, der mariadb-dump oder mysqldump mitbringt
  • Die Werkzeuge tar, gzip, flock und cron, 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/wordpress

Passen 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 pipefail bricht beim ersten Fehler ab, auch wenn der Fehler in einer Pipe auftritt. Ohne pipefail würde ein Datenbankfehler hinter | gzip verschwinden.
  • umask 077 sorgt dafür, dass neue Dateien nur für den Eigentümer lesbar sind.
  • flock -n verhindert 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. Der trap löscht Reste, wenn das Skript abbricht. So finden Sie im Zielordner nur vollständige Sicherungen.
  • --single-transaction reicht WP-CLI an mariadb-dump bzw. mysqldump durch. Bei InnoDB-Tabellen, dem Standard in aktuellen WordPress-Installationen, entsteht so ein konsistenter Stand, ohne die Website zu sperren.
  • Ausgeschlossen sind wp-content/cache und wp-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/wordpress

Im 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.php

Die 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 -e

und 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>&1

Das 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 SymptomUrsacheLösung
„wp: command not found“ nur im Cron-LaufCron nutzt einen knappen PATHexport PATH=… im Skript oder vollen Pfad zu wp
„Got error: 2005: "Unknown server host …"“Datenbankzugang kommt aus Umgebungsvariablen, die Cron nicht kenntVariablen oben in die Crontab eintragen
„Error: This does not seem to be a WordPress installation.“Falscher WP_PATHPfad zum Ordner mit wp-config.php eintragen
„Backup läuft bereits, Abbruch.“Vorheriger Lauf noch aktivLaufzeit prüfen, Cron-Zeitpunkt verschieben
Datenbankarchiv nur 20 Byte großExport ist gescheitert, leeres gzipSkript mit set -o pipefail nutzen, Log lesen
Keine Log-Datei, Cron scheint nicht zu laufenLog-Pfad nicht beschreibbar, etwa unter /var/logLog in den Backup-Ordner schreiben
Übrig gebliebene .part-DateienProzess wurde hart beendet, der trap lief nichtDateien 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.

Weiterführende Anleitungen und Quellen

WordPressBackupCronWP-CLILinux