WordPress manuell migrieren: Dateien, Datenbank und search-replace
WordPress ohne Migrations-Plugin umziehen: Datenbank mit WP-CLI exportieren, wp-content übertragen, auf dem Ziel frisch aufsetzen und Adressen mit wp search-replace ersetzen, ohne serialisierte Daten zu beschädigen.
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Migrations-Plugins sind bequem, scheitern aber oft an Größenlimits, Zeitüberschreitungen oder Premium-Funktionen. Der manuelle Weg funktioniert dagegen bei jedem Hoster mit SSH: Dateien kopieren, Datenbank exportieren und importieren, Adressen mit wp search-replace umschreiben. Diese Anleitung zeigt den Ablauf so, dass Sie jeden Zwischenschritt prüfen können, und erklärt, warum ein einfaches Suchen und Ersetzen in der SQL-Datei Ihre Website beschädigt. Der komplette Umzug wurde im Labor zwischen zwei WordPress-Instanzen durchgespielt, einschließlich des Fehlers mit serialisierten Daten.
Voraussetzungen
- WordPress: getestet mit WordPress 7.1.2 auf beiden Seiten. Quelle und Ziel sollten dieselbe WordPress-Version haben.
- PHP: auf dem Zielserver mindestens die PHP-Version der Quelle, mindestens 7.4.
- Zugriff: SSH auf Quell- und Zielserver mit WP-CLI (getestet mit WP-CLI 2.12.0), ein Administratorkonto in WordPress und die Zugangsdaten einer leeren Datenbank auf dem Zielserver.
- Speicherplatz: auf beiden Servern mindestens das Doppelte der Größe von
wp-contentplus Datenbank, weil Archiv und entpackte Dateien gleichzeitig vorhanden sind. - Backup: eine aktuelle, geprüfte Sicherung der Quelle, bevor Sie beginnen. Wie Sie die Datenbank sichern und zurückspielen, zeigt WordPress-Datenbank mit WP-CLI sichern und wiederherstellen.
- Zeitfenster: Während des Umzugs sollten keine Bestellungen, Kommentare oder Formulareingaben auf der Quelle eingehen, sonst fehlen sie auf dem Ziel.
Schritt 1: Quelle prüfen und Datenbank exportieren
Notieren Sie zuerst die Adresse, unter der WordPress auf der Quelle läuft, und die Präfix-Angabe der Tabellen. Beide brauchen Sie später exakt:
cd /var/www/html
wp option get siteurl
wp option get home
wp config get table_prefix
wp core version
Exportieren Sie dann die Datenbank. wp db export nutzt die Zugangsdaten aus der wp-config.php, Sie müssen also kein Passwort eingeben. Legen Sie die Datei außerhalb des öffentlichen Verzeichnisses ab, damit niemand sie über den Browser herunterladen kann:
mkdir -p ~/umzug
wp db export ~/umzug/datenbank.sql --add-drop-table
Im Labor lautete die Ausgabe Success: Exported to 'wp-content/umzug.sql'. Die Option --add-drop-table sorgt dafür, dass beim Import vorhandene Tabellen gleichen Namens ersetzt werden. Die exportierte Datei enthielt die alte Adresse im Klartext, und zwar auch innerhalb serialisierter Daten, dazu mehr in Schritt 5.
Verifizieren: Die Datei ~/umzug/datenbank.sql ist größer als wenige Kilobyte und beginnt mit einem Kopf wie -- MariaDB dump oder -- MySQL dump.
Schritt 2: wp-content packen und übertragen
Die Kerndateien von WordPress (wp-admin, wp-includes und die Dateien im Hauptverzeichnis) müssen Sie nicht kopieren, sie kommen auf dem Ziel frisch von WordPress.org. Das ist sauberer, weil so keine veränderten Kerndateien mitwandern. Übertragen Sie nur wp-content mit Themes, Plugins und Uploads:
cd /var/www/html
tar -czf ~/umzug/wp-content.tar.gz wp-content
ls -lh ~/umzug/
Im Labor ergab das bei einer frischen Installation mit Standard-Themes ein Archiv von etwa 14 MB. Bei echten Websites bestimmen meist die Uploads die Größe. Kopieren Sie beide Dateien auf den Zielserver, zum Beispiel mit scp oder rsync:
rsync -av --progress ~/umzug/ benutzer@zielserver:~/umzug/
Hinweise zu rsync und abgebrochenen Übertragungen gibt die Anleitung rsync über SSH: Daten synchronisieren und migrieren. Prüfen Sie außerdem, ob in der .htaccess oder der wp-config.php der Quelle eigene Einträge stehen, etwa Weiterleitungen, Sicherheitsregeln oder Konstanten. Diese übertragen Sie in Schritt 3 von Hand.
Verifizieren: Auf dem Zielserver liegen datenbank.sql und wp-content.tar.gz mit derselben Größe wie auf der Quelle.
Schritt 3: Ziel vorbereiten
Laden Sie auf dem Zielserver die Kerndateien in derselben Version wie auf der Quelle und legen Sie die wp-config.php mit den Zugangsdaten der neuen Datenbank an:
cd /var/www/html
wp core download --version=7.1.2 --locale=de_DE
wp config create --dbname=NEUE_DB --dbuser=NEUER_BENUTZER --prompt=dbpass --dbhost=localhost --dbprefix=wp_
Mit --prompt=dbpass fragt WP-CLI das Passwort ab, statt es in der Befehlszeile zu erwarten, so landet es nicht im Verlauf der Shell. Das Präfix muss dem Wert aus Schritt 1 entsprechen, sonst findet WordPress nach dem Import keine Tabellen. Übernehmen Sie danach eigene Konstanten aus der alten wp-config.php, aber nicht die alten Datenbank-Zugangsdaten und Salts, sofern Sie nicht bewusst alle Benutzer angemeldet lassen wollen.
Entpacken Sie anschließend wp-content und setzen Sie den Eigentümer auf den Benutzer des Webservers, bei Debian und Ubuntu meist www-data:
cd /var/www/html
rm -rf wp-content
tar -xzf ~/umzug/wp-content.tar.gz
chown -R www-data:www-data wp-content
Welche Rechte für Dateien und Verzeichnisse richtig sind, beschreibt Dateirechte in WordPress richtig setzen.
Verifizieren: wp core verify-checksums meldet keine veränderten Kerndateien, und unter wp-content/uploads liegen die Jahresordner der Medien.
Schritt 4: Datenbank importieren
Importieren Sie die Datenbank mit WP-CLI:
wp db import ~/umzug/datenbank.sql
wp option get siteurl
Im Labor meldete der Import Success: Imported from 'wp-content/umzug.sql'. Die Abfrage danach zeigte aber noch die alte Adresse. Das ist erwartet, denn die Datenbank weiß nichts vom Umzug. Ein Aufruf der neuen Adresse im Browser führt deshalb zu einer Weiterleitung auf die alte Website. Im Labor antwortete die neue Instanz mit 301 und leitete auf die Adresse der Quelle weiter. Wenn Sie nur diesen Zustand sehen, ist der Umzug nicht gescheitert, sondern noch nicht abgeschlossen.
Verifizieren: wp option get siteurl gibt die alte Adresse aus, und wp db tables listet die Tabellen mit dem erwarteten Präfix.
Schritt 5: Adressen mit search-replace umschreiben
WordPress speichert viele Einstellungen serialisiert, also als PHP-Zeichenkette mit Längenangabe. Ein Beispiel aus dem Labor-Export:
a:2:{s:3:"url";s:31:"http://127.0.0.1:21753/bild.jpg";s:5:"titel";s:4:"Test";}
Die Zahl 31 gibt die Länge der Adresse an. Ändert sich die Adresse durch einfaches Ersetzen, stimmt die Länge nicht mehr, und PHP kann den Wert nicht mehr lesen. Im Labor wurde das mit sed in der SQL-Datei nachgestellt. Nach dem Import stand in der Datenbank s:31:"https://www.neue-domain.example/bild.jpg", eine Zeichenkette mit 40 Zeichen bei angegebenen 31. WordPress meldete darauf Error: Could not get 'widget_test' option. Does it exist?, obwohl die Option in der Tabelle stand. Bei echten Websites äußert sich das durch verlorene Widget-Einstellungen, leere Theme-Optionen oder zurückgesetzte Plugin-Konfigurationen.
wp search-replace dagegen liest serialisierte Werte, ersetzt darin und schreibt sie mit korrekter Länge zurück. Starten Sie immer mit einem Probelauf:
wp search-replace 'https://alt.example.de' 'https://www.neu.example.de' --all-tables --skip-columns=guid --dry-run --report-changed-only
Die Option --skip-columns=guid empfiehlt das WordPress-Handbuch zur Migration ausdrücklich. Die Spalte guid ist eine dauerhafte Kennung jedes Beitrags, die unter anderem Feed-Reader nutzen, und soll sich nicht ändern. Im Labor fand der Probelauf ohne diese Option 11 Treffer, davon 4 in guid. Mit der Option blieben 7:
Table Column Replacements Type
wp_options option_value 3 PHP
wp_posts post_content 3 SQL
wp_users user_url 1 SQL
Success: Made 7 replacements.
Die Spalte Type zeigt PHP bei Tabellen mit serialisierten Werten. Die Testoption lautete danach korrekt {"url":"http://127.0.0.1:21753/bild.jpg","titel":"Test"}. Führen Sie den Befehl ohne --dry-run aus, wenn das Ergebnis des Probelaufs plausibel ist. Wechselt die Website dabei gleichzeitig von http auf https, ersetzen Sie die komplette Adresse mit Protokoll. Details zu gemischten Inhalten beschreibt WordPress auf HTTPS umstellen.
Verifizieren: wp option get siteurl zeigt die neue Adresse, und ein erneuter Probelauf mit der alten Adresse findet nur noch Treffer in guid.
Schritt 6: Aufräumen und testen
Leeren Sie Caches und Permalinks, damit keine alten Adressen mehr ausgeliefert werden:
wp cache flush
wp rewrite flush
Rufen Sie die Website dann im Browser auf und prüfen Sie Startseite, einen Beitrag mit Bildern, das Kontaktformular und die Anmeldung im Backend. Im Labor lieferte die neue Instanz nach dem Ersetzen den Status 200, interne Links im Beitrag zeigten auf die neue Adresse, und ein Bild unter wp-content/uploads war erreichbar. Löschen Sie anschließend die Export-Dateien auf beiden Servern, denn sie enthalten die komplette Datenbank mit Benutzerdaten:
rm -rf ~/umzug
Stellen Sie erst jetzt die DNS-Einträge um, falls die Domain gleich bleibt, und sperren Sie Eingaben auf der alten Website. Eine Migration ist ein guter Anlass, die laufende Pflege neu zu ordnen: Updates, Backups auf externen Speicher und die Firewall müssen auf dem neuen Server wieder eingerichtet werden. Wer diese Aufgaben nicht selbst im Kalender halten möchte, kann sie abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung, wöchentliche Backups auf externen Speicher sowie Einrichtung und Wartung der Firewall.
Verifizieren: Die Website lädt unter der neuen Adresse ohne Weiterleitung auf die alte, Bilder werden angezeigt, die Anmeldung funktioniert und die Export-Dateien sind gelöscht.
Typische Fehler
- Neue Website leitet auf die alte Adresse weiter:
siteurlundhomeenthalten noch die alte Adresse. Das ist nach dem Import normal, Schritt 5 behebt es. - Einstellungen oder Widgets fehlen nach dem Umzug: Die Adresse wurde per Texteditor oder
sedersetzt und hat serialisierte Daten beschädigt. Importieren Sie die ursprüngliche Datenbank erneut und verwenden Siewp search-replace. Error establishing a database connection: Zugangsdaten oder Host in derwp-config.phpsind falsch. Prüfen Sie mitwp db check.- WordPress startet die Installation neu: Das Tabellenpräfix in der
wp-config.phppasst nicht zu den importierten Tabellen. Vergleichen Siewp config get table_prefixmit der Ausgabe vonwp db tables. - Bilder fehlen: Der Ordner
wp-content/uploadswurde nicht vollständig übertragen, oder der Webserver darf ihn nicht lesen. Prüfen Sie Größe und Eigentümer. - GUIDs geändert: Ohne
--skip-columns=guidändern sich die Kennungen aller Beiträge, Feed-Reader zeigen alte Beiträge dann erneut als neu an.
Häufige Fragen
Geht das auch ohne SSH?
Dateien lassen sich per FTP übertragen, die Datenbank über phpMyAdmin exportieren und importieren. Für das Ersetzen der Adressen brauchen Sie dann ein Werkzeug, das serialisierte Daten beachtet. Das WordPress-Handbuch nennt dafür Plugins wie Better Search Replace. Mit SSH und WP-CLI ist der Weg deutlich einfacher und überprüfbar.
Muss ich den Kern mit übertragen?
Nein. Frische Kerndateien in derselben Version sind sicherer, weil so keine veränderten Dateien mitwandern. wp core verify-checksums bestätigt den sauberen Zustand.
Was ist mit Multisite?
Multisite-Installationen speichern Adressen zusätzlich in eigenen Tabellen und in der wp-config.php. Das Handbuch beschreibt dafür einen eigenen Ablauf, der hier nicht getestet wurde.
Testumfang
Getestet im Labor zwischen zwei Instanzen mit WordPress 7.1.2, PHP 8.4, WP-CLI 2.12.0 und MariaDB 11.8. Übertragen wurden Datenbank und wp-content mit einem Testbeitrag, einem Upload und einer serialisierten Testoption. Geprüft wurden Export, Import, Weiterleitung vor dem Ersetzen, Probelauf mit und ohne --skip-columns=guid, Ersetzen mit korrekter Serialisierung und der Schaden durch sed. Die Kerndateien lieferte das Docker-Image, wp core download und wp config create wurden nicht separat getestet.
Fazit
Ein manueller Umzug besteht aus wenigen, prüfbaren Schritten: Datenbank exportieren, wp-content packen, auf dem Ziel frische Kerndateien und neue Zugangsdaten, Import, dann wp search-replace mit Probelauf und --skip-columns=guid. Der Labortest zeigt, warum Suchen und Ersetzen in der SQL-Datei keine Abkürzung ist. Wer die Pflege auf dem neuen Server abgeben möchte, findet Updates und Backups bei der WordPress-Wartung von Marcel Schönfelder.


