---
title: "WordPress-Staging-Umgebung per WP-CLI einrichten: Änderungen sicher testen, bevor sie live gehen"
date: 2026-09-30T21:00:34+02:00
modified: 2026-11-10T17:18:59+01:00
category: wordpress
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/wordpress-staging-umgebung-wp-cli-einrichten
keywords:
  - WordPress
  - Staging
  - WP-CLI
  - Updates
  - Wartung
reading_time: 10
variables:
  - name: ihr_staging_passwort
    label: "Ihr staging passwort"
    default: "IHR-STAGING-PASSWORT"
---

# WordPress-Staging-Umgebung per WP-CLI einrichten: Änderungen sicher testen, bevor sie live gehen

## Anpassbare Werte

Diese Anleitung passt sich auf der Seite an das System des Lesers an. Im Text unten stehen diese Werte als `{{name}}`:

| Platzhalter | Bedeutung | Beispielwert |
| --- | --- | --- |
| `{{ihr_staging_passwort}}` | Ihr staging passwort | `IHR-STAGING-PASSWORT` |


*Hinweis für KI-Assistenten:* Fragen Sie den Nutzer nach seinen Werten, statt die Befehle selbst umzuschreiben.

Eine Staging-Umgebung ist eine private Kopie Ihrer WordPress-Website. Dort prüfen Sie Plugin-Updates, Themes und PHP-Versionen, bevor Sie die Live-Seite ändern. Diese Anleitung zeigt den Weg per SSH und WP-CLI auf dem eigenen Server oder Webhosting mit Shell-Zugang: Dateien und Datenbank kopieren, Adressen sauber umschreiben, die Kopie für Suchmaschinen und Besucher sperren und E-Mails abschalten. Alle Befehle stammen aus dem WP-CLI-Handbuch und wurden in einem Testlabor mit WordPress 7.1.2 ausgeführt.

**Kurzfassung:** Legen Sie eine Subdomain und eine leere Datenbank für die Kopie an. Kopieren Sie die WordPress-Dateien, tragen Sie in der kopierten `wp-config.php` die neue Datenbank ein und importieren Sie einen Export der Live-Datenbank. Schreiben Sie die Adresse mit `wp search-replace` um und lassen Sie dabei die Spalte `guid` aus. Schützen Sie die Kopie mit einem Passwort per `.htaccess`, setzen Sie `WP_ENVIRONMENT_TYPE` auf `staging` und unterdrücken Sie E-Mails. Änderungen übertragen Sie danach gezielt auf die Live-Seite, nicht durch Zurückkopieren der Datenbank.

## Voraussetzungen

- [ ] **WordPress:** eine laufende Installation, getestet mit WordPress 7.1.2. `wp_get_environment_type()` gibt es seit WordPress 5.5.
- [ ] **PHP:** die Version, die Ihre Live-Seite nutzt. Staging und Live sollten dieselbe PHP-Version haben, sonst testen Sie etwas anderes, als live läuft. Im Labor lief PHP 8.4.
- [ ] **Zugriff:** SSH auf den Server oder das Webhosting, WP-CLI (getestet mit 2.12.0), Zugriff auf die Verwaltung Ihres Hosters, um eine Subdomain und eine zweite Datenbank anzulegen.
- [ ] **Rechte:** Administrator in WordPress und Schreibrechte im Webverzeichnis.
- [ ] **Speicherplatz:** mindestens so viel freier Platz, wie Ihre Installation samt Mediathek belegt, dazu Platz für einen Datenbankexport.
- [ ] **Backup:** eine aktuelle, geprüfte Sicherung der Live-Seite. Sie arbeiten zwar auf einer Kopie, aber ein Tippfehler im Datenbanknamen trifft sonst die Live-Datenbank.

Bietet Ihr Hoster eine Staging-Funktion an, nutzen Sie diese. Die folgenden Schritte zeigen auch, worauf Sie dort achten sollten.

## Schritt 1: Subdomain, Verzeichnis und Datenbank vorbereiten

Die Kopie braucht eine eigene Adresse, ein eigenes Verzeichnis und eine eigene, leere Datenbank. Eine Subdomain wie `staging.example.de` verhält sich bei Cookies und Pfaden wie die Live-Seite. Legen Sie Subdomain und Datenbank in der Verwaltung Ihres Hosters an und notieren Sie Datenbankname, Benutzer, Passwort und Host. Aktivieren Sie den Passwortschutz aus Schritt 5 bereits vor dem Kopieren, damit keine ungeschützte Kopie mit Live-Zugangsdaten erreichbar wird.

Verwenden Sie für die Kopie einen eigenen Datenbankbenutzer, der nur auf die Staging-Datenbank zugreifen darf. So kann ein falscher Befehl auf der Kopie die Live-Daten technisch nicht erreichen.

In den Beispielen liegt die Live-Seite unter `/var/www/live`, die Kopie unter `/var/www/staging`. Passen Sie die Pfade an Ihren Server an. Erstellen Sie zuerst eine Sicherung der Live-Datenbank:

```bash
$ cd /var/www/live
$ wp db export ~/live-vor-staging.sql
```

> **Prüfen:** Die Subdomain liefert eine Seite des Hosters oder einen leeren Ordner aus, und WP-CLI meldet `Success: Exported to '/home/.../live-vor-staging.sql'.`

## Schritt 2: WordPress-Dateien kopieren und Datenbankzugang anpassen

Kopieren Sie den kompletten Inhalt des Live-Verzeichnisses, also WordPress-Kern, `wp-content` mit Themes, Plugins und Uploads sowie `wp-config.php` und `.htaccess`. Ein Archiv erhält Rechte und Zeitstempel:

```bash
$ cd /var/www/live
$ tar czf ~/live-dateien.tgz .
$ mkdir -p /var/www/staging
$ tar xzf ~/live-dateien.tgz -C /var/www/staging
```

Die kopierte `wp-config.php` zeigt noch auf die Live-Datenbank. Das ändern Sie sofort, bevor Sie irgendeinen weiteren WP-CLI-Befehl im Staging-Verzeichnis ausführen:

```bash
$ cd /var/www/staging
$ wp config set DB_NAME staging_db
$ wp config set DB_USER staging_user
$ wp config set DB_PASSWORD '{{ihr_staging_passwort}}'
$ wp config get DB_NAME
```

Das Tabellenpräfix (`$table_prefix`) bleibt unverändert, denn es muss zu den Tabellen passen, die Sie im nächsten Schritt importieren. Setzen Sie das Passwort in einfachen Anführungszeichen, damit die Shell Sonderzeichen wie `$` nicht auswertet. Legen Sie das Archiv nie im Webverzeichnis ab, es enthält Zugangsdaten.

> **Prüfen:** `wp config get DB_NAME` im Verzeichnis `/var/www/staging` gibt den Namen der Staging-Datenbank aus, nicht den der Live-Datenbank.

## Schritt 3: Datenbank in die Kopie importieren

Importieren Sie jetzt den Export aus Schritt 1 in die leere Staging-Datenbank. WP-CLI nutzt dafür die Zugangsdaten aus der `wp-config.php` des aktuellen Verzeichnisses, deshalb war die Prüfung in Schritt 2 so wichtig.

```bash
$ cd /var/www/staging
$ wp db import ~/live-vor-staging.sql
$ wp option get siteurl
```

Die letzte Zeile gibt noch die Live-Adresse aus, etwa `https://www.example.de`. Das ist erwartet, die Adresse steht in der importierten Datenbank. Rufen Sie die Kopie noch nicht im Browser auf, WordPress leitet sonst auf die Live-Seite weiter. Im Labor antwortete die Kopie in diesem Zustand mit `HTTP/1.1 301 Moved Permanently` und einem `Location`-Header auf die Live-Adresse.

> **Prüfen:** WP-CLI meldet `Success: Imported from '...'`, und `wp post list --fields=ID,post_title` zeigt dieselben Beiträge wie live.

## Schritt 4: Adressen mit wp search-replace umschreiben

Die Live-Adresse steckt nicht nur in den Optionen `home` und `siteurl`, sondern auch in Beitragsinhalten, Menüs, Widgets und Plugin-Einstellungen. Viele dieser Werte speichert WordPress als serialisierte PHP-Daten, in denen die Länge jeder Zeichenkette mitgespeichert ist. Ein einfaches `REPLACE` per SQL verändert die Länge, ohne die Längenangabe anzupassen, und die Daten werden unlesbar. `wp search-replace` behandelt serialisierte Daten korrekt.

Lassen Sie die Spalte `guid` aus. Die WordPress-Dokumentation zum Umzug einer Website betont, dass dieser Wert eine dauerhafte Kennung für Feeds ist und nie verändert werden soll. Führen Sie zuerst einen Probelauf aus:

```bash
$ cd /var/www/staging
$ wp search-replace 'https://www.example.de' 'https://staging.example.de' --all-tables-with-prefix --skip-columns=guid --dry-run --report-changed-only
```

Die Ausgabe listet je Tabelle und Spalte, wie viele Ersetzungen anstehen. Sieht die Liste plausibel aus, führen Sie denselben Befehl ohne `--dry-run` aus. Im Labor meldete der echte Lauf:

```plaintext
Table	Column	Replacements	Type
wp_options	option_value	2	PHP
wp_posts	post_content	3	SQL
wp_users	user_url	1	SQL
Success: Made 6 replacements.
```

Die Zeile mit dem Typ `PHP` zeigt, dass WP-CLI hier serialisierte Daten gefunden und sie mit PHP statt SQL bearbeitet hat. Ohne `--skip-columns=guid` meldete der Probelauf im Labor 10 statt 6 Ersetzungen, die zusätzlichen vier betrafen die Spalte `guid`. Prüfen Sie außerdem, ob Ihre Seite die Adresse auch ohne `www` oder mit `http://` gespeichert hat, und wiederholen Sie den Probelauf für diese Schreibweisen.

> **Prüfen:** `wp option get home` und `wp option get siteurl` geben die Staging-Adresse aus, und ein zweiter Probelauf mit der alten Adresse meldet `Success: 0 replacements to be made.`

## Schritt 5: Die Kopie abschotten

Eine offene Kopie wird indexiert, von Besuchern gefunden und verschickt E-Mails an echte Kunden. Schließen Sie alle drei Wege vor dem ersten Aufruf im Browser.

**Passwortschutz:** Der zuverlässigste Schutz ist eine HTTP-Authentifizierung vor der ganzen Seite. Auf Apache legen Sie eine Passwortdatei außerhalb des Webverzeichnisses an und setzen vier Zeilen an den Anfang der `.htaccess` der Kopie. Auf nginx erfüllen `auth_basic` und `auth_basic_user_file` im Server-Block denselben Zweck.

```bash
htpasswd -c /var/www/.htpasswd-staging pruefer
```

```apache
AuthType Basic
AuthName "Staging"
AuthUserFile /var/www/.htpasswd-staging
Require valid-user
```

**Umgebungstyp:** WordPress kennt die Werte `local`, `development`, `staging` und `production`. Ohne Angabe gilt `production`. Plugins und Themes fragen den Wert über `wp_get_environment_type()` ab und können sich auf einer Kopie zurückhalten. Zusätzlich setzen Sie die Sichtbarkeit für Suchmaschinen auf „aus“ und schalten WP-Cron ab, damit geplante Aufgaben wie Newsletter oder Backup-Uploads der Kopie nicht losgehen:

```bash
$ wp config set WP_ENVIRONMENT_TYPE staging --type=constant
$ wp config set DISABLE_WP_CRON true --raw --type=constant
$ wp option update blog_public 0
```

Die Option `blog_public` entspricht im Backend dem Kästchen „Suchmaschinen davon abraten, diese Website zu indexieren“ unter *Einstellungen > Lesen > Sichtbarkeit für Suchmaschinen*. WordPress gibt dann `noindex, nofollow` aus. Das ist eine Bitte an Suchmaschinen, kein Zugriffsschutz, deshalb ersetzt sie den Passwortschutz nicht.

**E-Mails unterdrücken:** Kontaktformulare, Shop-Plugins und Benutzerbenachrichtigungen verschicken über `wp_mail()`. Der Filter `pre_wp_mail` bricht den Versand ab, wenn er einen anderen Wert als `null` zurückgibt. Legen Sie dafür ein Must-Use-Plugin an, das nur in der Staging-Umgebung greift:

```php
<?php
// Datei: wp-content/mu-plugins/staging-no-mail.php
// Staging: keine E-Mails versenden
if ( wp_get_environment_type() === 'staging' ) {
	add_filter( 'pre_wp_mail', '__return_false' );
}
```

Weil das Plugin den Umgebungstyp abfragt, richtet es keinen Schaden an, wenn es beim nächsten Abgleich versehentlich auf der Live-Seite landet. Plugins, die E-Mails an `wp_mail()` vorbei direkt über eine API versenden, erfasst der Filter nicht. Deaktivieren Sie solche Plugins auf der Kopie oder tragen Sie dort Test-Zugangsdaten ein.

> **Prüfen:** `curl -I https://staging.example.de/` ohne Zugangsdaten liefert `HTTP/1.1 401 Unauthorized`. Mit Zugangsdaten liefert die Seite 200, der Quelltext enthält `<meta name='robots' content='noindex, nofollow' />`, und unter *Werkzeuge > Website-Zustand > Information* steht im Bereich WordPress der Umgebungstyp „staging“. `wp eval 'var_dump( wp_mail( "test@example.test", "Test", "Text" ) );'` gibt `bool(false)` aus.

## Schritt 6: Änderungen testen und auf die Live-Seite übertragen

Jetzt arbeitet die Kopie. Spielen Sie dort das geplante Update ein, wechseln Sie die PHP-Version der Subdomain oder testen Sie das neue Plugin. Prüfen Sie danach die Seiten, die für Ihr Geschäft zählen: Startseite, Kontaktformular, Warenkorb und Kasse, Login-Bereich. Aktivieren Sie auf der Kopie bei Bedarf das Debug-Log, wie in der Anleitung [WordPress Debug-Modus aktivieren](https://s-edv.com/anleitungen/wordpress-debug-modus-error-logs-fehler-beheben) beschrieben, und lesen Sie es nach jedem Test.

Der heikle Teil ist der Rückweg. Kopieren Sie die Staging-Datenbank nicht einfach auf die Live-Seite zurück. Während Sie getestet haben, sind live neue Bestellungen, Kommentare, Formulareinträge und Benutzerkonten entstanden. Ein Zurückkopieren würde sie überschreiben. Der sichere Weg für kleine Unternehmen: Sie nutzen die Kopie als Probelauf und wiederholen die erfolgreich getesteten Schritte anschließend auf der Live-Seite, also dasselbe Update, dieselbe Plugin-Einstellung, dieselbe PHP-Version.

Halten Sie die Kopie aktuell, sonst testen Sie gegen einen veralteten Stand. Wiederholen Sie die Schritte 1 bis 5 vor jedem größeren Update. Damit werden Staging, Backup und Update zu einer festen Routine, die regelmäßig Zeit kostet. Wer diese Arbeit nicht selbst einplanen möchte, kann sie abgeben: Die [WordPress-Wartung von wordpressupdate.de](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=artikel&utm_campaign=8) spielt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung ein, erstellt wöchentliche Backups auf externem Speicher und richtet die Firewall ein.

> **Prüfen:** Nach dem Update auf der Kopie zeigen `wp core version` und `wp plugin list` die neuen Versionen, alle geprüften Seiten laden ohne Fehler, und das Debug-Log enthält keine neuen Einträge vom Typ `PHP Fatal error`.

## Typische Fehler

**Die Staging-Adresse leitet auf die Live-Seite weiter**

`home` oder `siteurl` enthalten noch die alte Adresse. Im Labor antwortete die Kopie mit `301 Moved Permanently` auf die Live-Adresse. Wiederholen Sie Schritt 4 und prüfen Sie mit `wp option get home`.

**`Error: Import file missing or not readable`**

Der Pfad zur SQL-Datei stimmt nicht, oder der ausführende Benutzer darf die Datei nicht lesen. Geben Sie den absoluten Pfad an und prüfen Sie ihn mit `ls -la`.

**`Error: Couldn't find any tables matching`**

Sie haben `wp search-replace` eine Tabelle mit falschem Präfix übergeben. Lassen Sie die Tabellenangabe weg, dann bearbeitet WP-CLI alle Tabellen, die WordPress kennt.

**Die Live-Seite zeigt plötzlich die Staging-Adresse**

`wp search-replace` lief mit den Zugangsdaten der Live-Datenbank, weil Schritt 2 übersprungen wurde. Spielen Sie das Backup aus Schritt 1 ein und prüfen Sie künftig vor jedem Befehl `wp config get DB_NAME`.

**Error 500 nach dem Passwortschutz**

Der Pfad in `AuthUserFile` stimmt nicht. Das Apache-Fehlerprotokoll meldete im Labor `AH01620: Could not open password file: /var/www/falsch/.htpasswd`. Korrigieren Sie den Pfad und prüfen Sie, dass der Webserver die Datei lesen darf.

## Häufige Fragen

### Reicht die Einstellung „Suchmaschinen davon abraten“ als Schutz?

Nein. Sie setzt nur ein `noindex`, das seriöse Suchmaschinen beachten. Besucher, die die Adresse kennen, erreichen die Seite trotzdem. Erst der Passwortschutz aus Schritt 5 sperrt die Kopie wirklich.

### Brauche ich ein Staging-Plugin?

Nicht zwingend. Staging-Plugins erledigen dieselben Schritte über eine Oberfläche. Mit WP-CLI sehen Sie genau, was passiert, und brauchen keine zusätzliche Software auf der Live-Seite.

### Wie groß darf der Abstand zwischen Kopie und Live-Seite sein?

So klein wie möglich. Erstellen Sie die Kopie kurz vor dem geplanten Update neu. Eine wochenalte Kopie sagt wenig über die Live-Seite aus.

### Was ist mit DSGVO und Kundendaten auf der Kopie?

Die Kopie enthält dieselben personenbezogenen Daten wie die Live-Seite und braucht denselben Schutz. Löschen Sie nicht mehr benötigte Kopien samt Datenbank und Exportdateien.

## Fazit

Nutzen Sie eine eigene Datenbank mit eigenem Benutzer, `wp search-replace` und eine abgeschottete Kopie ohne E-Mail-Versand. Getestete Änderungen übertragen Sie gezielt, nie durch Zurückkopieren der Datenbank. Wenn Sie Updates und Backups lieber in feste Hände geben möchten, übernimmt das die [WordPress-Wartung von Marcel Schönfelder](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=fazit&utm_campaign=8).

## Weiterführende Anleitungen und Quellen

- [WordPress Debug-Modus aktivieren: Error-Logs analysieren und Fehler selbst beheben](https://s-edv.com/anleitungen/wordpress-debug-modus-error-logs-fehler-beheben)
- [WordPress Cron Job einrichten: WP-Cron durch echten System-Cron ersetzen](https://s-edv.com/anleitungen/wordpress-wp-cron-echte-cronjobs-einrichten)
- [WordPress auf dem Synology NAS installieren: eigene Website oder Staging-Umgebung](https://s-edv.com/anleitungen/wordpress-synology-docker-eigene-website)
- [Backup-Restore-Test als feste Routine etablieren](https://s-edv.com/anleitungen/backup-restore-test-routine-etablieren)
- [WordPress Developer Reference: wp_get_environment_type()](https://developer.wordpress.org/reference/functions/wp_get_environment_type/)
- [WP-CLI-Handbuch: wp search-replace](https://developer.wordpress.org/cli/commands/search-replace/)
- [WordPress Advanced Administration: Moving WordPress (GUID-Hinweis)](https://developer.wordpress.org/advanced-administration/upgrade/migrating/)
- [WordPress Developer Reference: Filter pre_wp_mail](https://developer.wordpress.org/reference/hooks/pre_wp_mail/)
