WordPress auf einen neuen Server umziehen, ohne Ausfall
Die Reihenfolge entscheidet: neuen Server vorbereiten, Daten kopieren, per hosts-Datei unter der echten Domain testen, Zertifikat vorab ausstellen, erst danach DNS umstellen. Mit Rückweg und echten Fehlermeldungen.
Ein WordPress-Umzug scheitert selten an einem einzelnen Befehl. Er scheitert an der Reihenfolge. Wer zuerst DNS umstellt und danach kopiert, hat garantiert eine Lücke, in der Besucher entweder eine Fehlerseite oder eine halb befüllte Installation sehen. Wer umgekehrt vorgeht, kann den neuen Server in Ruhe fertigstellen, unter der echten Domain testen und den DNS-Eintrag erst in dem Moment ändern, in dem alles nachweislich läuft.
Dieser Artikel beschreibt genau diese Reihenfolge, dazu die Stellen, an denen es in der Praxis knallt: serialisierte Daten in der Datenbank, Kollationen beim Wechsel von MySQL zu MariaDB, Zertifikate ohne zeigenden DNS-Eintrag und der Rückweg, falls doch etwas übersehen wurde.
Der Ablauf, der keinen Ausfall erzeugt
Die alte Seite bleibt bis zum letzten Moment online. Nichts wird abgeschaltet, nichts wird gelöscht. Der neue Server läuft parallel, wird getestet und übernimmt erst, wenn der DNS-Eintrag umgestellt ist.
- TTL des A- und AAAA-Records auf 300 Sekunden senken, mindestens 24 bis 48 Stunden vorher.
- Neuen Server aufsetzen: Webserver, PHP, Datenbank, Benutzer, Verzeichnisse.
- Dateien kopieren, Datenbank kopieren.
- Zertifikat für die Domain ausstellen, obwohl DNS noch auf den alten Server zeigt.
- Auf dem eigenen Rechner die hosts-Datei anpassen und die Seite unter der echten Domain durchklicken.
- Kurz vor dem Schnitt einen Delta-Sync fahren, damit die letzten Änderungen mitkommen.
- DNS umstellen. Alten Server noch mehrere Tage laufen lassen.
Der einzige Punkt, an dem theoretisch eine Lücke entsteht, ist Schritt 6. Wie klein die wird, entscheidet Schritt 1.
TTL senken, bevor irgendetwas anderes passiert
Die TTL sagt Resolvern weltweit, wie lange sie eine Antwort zwischenspeichern dürfen. Steht sie auf 86400, kann ein Resolver Ihre alte IP noch 24 Stunden lang ausliefern, nachdem Sie umgestellt haben. Und, das wird gern übersehen: Eine gesenkte TTL wirkt erst, nachdem die alte TTL abgelaufen ist. Wenn Sie von 86400 auf 300 gehen, kann es einen Tag dauern, bis alle Resolver den kurzen Wert kennen.
Deshalb ist das der erste Handgriff, nicht der letzte. dig gehört auf keiner Distribution zur Grundausstattung und wird in dieser Anleitung durchgehend gebraucht, installieren Sie es also zuerst:
apt install -y bind9-dnsutils
Auf Debian 11, Ubuntu 22.04 und Ubuntu 24.04 heißt das Paket noch dnsutils. Ab Debian 12 ist dnsutils nur noch ein Platzhalter, der auf bind9-dnsutils verweist, auf Debian 13 sogar ein rein virtuelles Paket ohne eigene Version. Funktionieren tut beides, weil apt den einzigen Anbieter selbst auflöst, aber bind9-dnsutils ist der Name, der bleibt. Danach den aktuellen Wert prüfen:
dig +noall +answer example.com A
dig +noall +answer example.com SOA
Die Zahl in der zweiten Spalte der A-Antwort ist die verbleibende TTL. Beim Autoritativen fragen Sie direkt nach, sonst sehen Sie nur den Restwert aus dem Cache Ihres Resolvers:
dig @a.ns14.net example.com A +noall +answer
Nach dem Umzug setzen Sie die TTL wieder hoch, 3600 oder mehr. Dauerhaft kurze TTLs erzeugen unnötige Last und verlängern Ausfälle Ihres DNS-Anbieters.
Den neuen Server passend bestücken
Hier entstehen die meisten bösen Überraschungen, weil die Distribution auf dem neuen Server anders liefert als die alte. Alle Paketbefehle dieser Anleitung gehen von Debian oder Ubuntu aus, auf AlmaLinux, Rocky Linux und Oracle Linux gibt es kein apt und die Paketnamen weichen ab. Stand Juli 2026 sieht es so aus:
| System | PHP | Datenbank | nginx |
|---|---|---|---|
| Debian 13 | 8.4 | MariaDB 11.8 (kein mysql-server) | 1.26.3 |
| Debian 12 | 8.2 | MariaDB 10.11 | 1.22.1 |
| Ubuntu 24.04 | 8.3 | MySQL 8.0.46 oder MariaDB 10.11 | 1.24.0 |
| Ubuntu 22.04 | 8.1 | MySQL 8.0.46 oder MariaDB 10.6 | 1.18.0 |
Zwei Konsequenzen daraus. Erstens: Auf Debian bekommen Sie kein mysql-server, dort läuft immer MariaDB. Wenn die alte Seite auf MySQL 8 lief, ist der Umzug nach Debian gleichzeitig ein Datenbankwechsel, mit einer sehr konkreten Falle weiter unten. Zweitens: Der Sprung von PHP 8.1 auf 8.4 ist kein Selbstläufer. Ältere Themes und Plugins reagieren auf entfernte Funktionen mit einem Fatal error: Uncaught Error: Call to undefined function oder mit einer weißen Seite. Wenn die alte Installation auf PHP 8.1 lief und Sie den Umzug nicht mit einem PHP-Upgrade koppeln wollen, ist Ubuntu 22.04 oder eine PHP-Version aus einem Fremdrepository die ruhigere Wahl. Was in der Tabelle bewusst fehlt, ist Debian 11: Dort liefert php-cli noch PHP 7.4.33, also eine Version ohne Sicherheitspflege und unterhalb dessen, was WordPress empfiehlt. Als Ziel eines Umzugs scheidet Debian 11 damit aus, es sei denn, Sie binden vorher das Sury-Repository ein.
Die Basispakete für eine typische Installation mit nginx und PHP-FPM:
apt update
apt install -y nginx php-fpm php-mysql php-xml php-curl php-mbstring php-zip php-gd php-intl
apt install -y mariadb-server mariadb-client rsync curl
Details zum Webserver stehen in der nginx-Anleitung, die Grundabsicherung der Datenbank in MariaDB und MySQL absichern. Wenn der Server frisch ist, lohnt vorher ein Blick in die Checkliste für neue Rootserver.
Datenbank und Benutzer anlegen, mit demselben Zeichensatz wie auf der Quelle:
CREATE DATABASE wp_neu CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_neu'@'localhost' IDENTIFIED BY 'ein-langes-passwort';
GRANT ALL PRIVILEGES ON wp_neu.* TO 'wp_neu'@'localhost';
FLUSH PRIVILEGES;
Dateien übertragen, ohne die Rechte zu zerschießen
Kopiert wird direkt von Server zu Server, nicht über den heimischen Anschluss. Am einfachsten per rsync vom alten auf den neuen Server, mit einem SSH-Key statt Passwort:
rsync -az --delete --exclude 'wp-content/cache/' --exclude 'wp-content/uploads/backup*' \
-e 'ssh -p 22' /var/www/html/ root@neue.ip:/var/www/html/
Der erste Lauf darf dauern. Genau deshalb macht man ihn Tage vor dem Schnitt und kurz davor nur noch einmal denselben Befehl, der dann nur die Unterschiede überträgt.
Nach dem Kopieren gehören Eigentümer und Rechte gerade gezogen, denn UIDs unterscheiden sich zwischen Systemen und rsync überträgt Zahlen, nicht Namen:
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 640 /var/www/html/wp-config.php
Zwei Dateien fliegen vor dem ersten Start raus, falls vorhanden: wp-content/object-cache.php und wp-content/advanced-cache.php. Beides sind Drop-ins von Caching-Plugins, die auf einen Redis- oder Memcached-Socket zeigen, den es auf dem neuen Server noch nicht gibt. Das Ergebnis wäre eine weiße Seite ohne verwertbare Meldung.
Die Datenbank übertragen und die Kollations-Falle
Der Dump geht mit WP-CLI oder klassisch. WP-CLI hat den Vorteil, dass es Zeichensatz und Präfix aus der wp-config.php nimmt:
cd /var/www/html
wp db export /root/wp-dump.sql --add-drop-table
Ohne WP-CLI, auf einem aktuellen MariaDB-System heißt das Werkzeug mariadb-dump. Der alte Name mysqldump ist ab MariaDB 11.0 nur noch ein veralteter Symlink und quittiert den Dienst mit Deprecated program name. It will be removed in a future release:
mariadb-dump --single-transaction --default-character-set=utf8mb4 wp_alt > /root/wp-dump.sql
Jetzt die Stelle, an der ein Umzug von Ubuntu mit MySQL 8 auf Debian mit MariaDB regelmäßig auf die Nase fällt. MySQL 8 verwendet standardmäßig die Kollation utf8mb4_0900_ai_ci, die es in MariaDB überhaupt nicht gibt. Der Import bricht ab mit:
ERROR 1273 (HY000) at line 42: Unknown collation: 'utf8mb4_0900_ai_ci'
Reparatur vor dem Import, direkt im Dump:
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g; s/utf8mb4_0900_as_cs/utf8mb4_unicode_ci/g' /root/wp-dump.sql
grep -c utf8mb4_unicode_ci /root/wp-dump.sql
Danach importieren:
mariadb --default-character-set=utf8mb4 wp_neu < /root/wp-dump.sql
Wenn nach dem Import überall für statt für steht, ist der Zeichensatz beim Dump oder beim Import verlorengegangen. Das repariert man nicht mit Suchen und Ersetzen, sondern indem man Dump und Import mit --default-character-set=utf8mb4 wiederholt. Deshalb ist die alte Datenbank zu diesem Zeitpunkt noch unangetastet vorhanden.
Anschließend die Zugangsdaten in der wp-config.php auf dem neuen Server anpassen: DB_NAME, DB_USER, DB_PASSWORD, und ganz wichtig DB_HOST, falls die alte Installation auf einen entfernten Datenbankserver zeigte. Bleibt dort die alte Adresse stehen, sehen Sie Error establishing a database connection, obwohl lokal alles läuft. Falls die Verbindung trotz korrekter Daten klemmt, hilft Access denied for user beheben.
Die Domain ersetzen, und warum ein SQL-Replace die Seite zerlegt
Zuerst die gute Nachricht: Wenn sich nur der Server ändert und die Domain gleich bleibt, müssen Sie in der Datenbank gar nichts ersetzen. Genau das ist einer der Gründe, warum der Test über die hosts-Datei dem Test über eine Behelfsdomain überlegen ist. Nötig wird das Ersetzen nur, wenn die Domain tatsächlich wechselt, wenn Sie den Umzug mit dem Schritt von http auf https verbinden oder wenn Sie doch mit einer Testdomain arbeiten und hinterher zurückersetzen müssen.
Und jetzt der Grund, warum man das niemals mit einem einfachen SQL-Befehl macht. WordPress speichert Optionen, Widget-Einstellungen und Theme-Konfigurationen als serialisierte PHP-Arrays. Eine URL steht darin nicht nackt, sondern mit ihrer Bytelänge davor:
s:19:"https://example.com"
Ersetzen Sie example.com per UPDATE ... REPLACE() durch neue-domain.de, wird der String länger, die Zahl 19 bleibt aber stehen. PHP kann das Array danach nicht mehr entpacken, unserialize() liefert false und die betroffene Einstellung ist weg. Typische Symptome: Widgets verschwunden, Theme-Optionen zurückgesetzt, Menüpunkte leer, in den Logs Notice: unserialize(): Error at offset.
WP-CLI löst das richtig, weil es die Daten entpackt, ersetzt und mit korrigierter Längenangabe neu schreibt. Immer erst mit --dry-run:
wp search-replace 'https://alte-domain.de' 'https://neue-domain.de' --all-tables --precise --dry-run --report-changed-only
Was die einzelnen Schalter tun: --all-tables fasst auch Tabellen an, die nicht dem WordPress-Präfix folgen, etwa von Shop- oder Formular-Plugins. --precise erzwingt die Verarbeitung in PHP statt in SQL, ist langsamer, behandelt serialisierte Daten aber zuverlässig. --report-changed-only kürzt die Ausgabe auf die Tabellen mit echten Treffern.
Sieht die Vorschau plausibel aus, denselben Befehl ohne --dry-run laufen lassen. Danach kommt der Durchgang, den fast alle Anleitungen auslassen: Page-Builder wie Elementor speichern ihre Inhalte als JSON in der Datenbank, und dort sind Schrägstriche maskiert. Ein Ersetzen von https://alte-domain.de findet https:\/\/alte-domain.de schlicht nicht. Deshalb ein zweiter Lauf:
wp search-replace 'https:\/\/alte-domain.de' 'https:\/\/neue-domain.de' --all-tables --precise --report-changed-only
Bei Elementor gehört anschließend im Backend unter Werkzeuge das Regenerieren der CSS-Dateien dazu, sonst zeigen die erzeugten Stylesheets weiter auf die alte Domain.
Zwei Dinge, die search-replace nicht erreicht: Konstanten in der wp-config.php und Multisite. Steht dort define('WP_HOME', 'https://alte-domain.de');, überschreibt das jeden Datenbankwert, und Sie suchen stundenlang im falschen Ort. Bei Multisite brauchen Sie zusätzlich --network und müssen die Domains in wp_blogs und wp_site anpassen.
Und eine Warnung zum Tabellenpräfix: Ändern Sie es beim Umzug nicht. Das Präfix steckt auch im Optionsnamen wp_user_roles und in den Benutzermetafeldern wp_capabilities und wp_user_level. Wer nur die Tabellen umbenennt, kann sich zwar noch einloggen, bekommt danach aber Sorry, you are not allowed to access this page. und hat keinen Administrator mehr.
Zertifikat ausstellen, bevor DNS zeigt
Hier steckt ein Henne-Ei-Problem. Die übliche HTTP-Validierung von Let's Encrypt verlangt, dass der Domainname bereits auf den validierenden Server zeigt. Das tut er zu diesem Zeitpunkt aber noch nicht, denn er soll ja noch die alte Seite ausliefern. Wer trotzdem certbot --nginx startet, bekommt:
Certbot failed to authenticate some domains (authenticator: nginx).
Invalid response from http://example.com/.well-known/acme-challenge/...: 404
Der saubere Ausweg ist die DNS-Validierung. Die prüft einen TXT-Eintrag _acme-challenge.example.com und interessiert sich nicht dafür, wohin der A-Record zeigt:
certbot certonly --manual --preferred-challenges dns -d example.com -d www.example.com
Certbot zeigt einen Wert an, den Sie als TXT-Eintrag in Ihrer DNS-Zone hinterlegen. Vor dem Bestätigen unbedingt selbst nachsehen, ob die Zone den Eintrag schon ausliefert, sonst verbrennen Sie einen Fehlversuch:
dig +short TXT _acme-challenge.example.com
Bei Wildcard-Domains oder wenn Sie das automatisieren wollen, steht der Weg über die DNS-API im Beitrag zum Wildcard-Zertifikat. Die manuelle Variante erneuert sich nicht von selbst, deshalb stellen Sie nach dem DNS-Schnitt auf die normale HTTP-Validierung um. Ab dann funktioniert sie, weil die Domain jetzt auf den neuen Server zeigt.
Mit der hosts-Datei testen, wie ein echter Besucher
Jetzt kommt der Teil, der den Unterschied zwischen "sollte gehen" und "geht" ausmacht. Sie lenken nur Ihren eigenen Rechner auf den neuen Server, während der Rest der Welt weiter die alte Seite sieht.
Unter Linux und macOS bearbeiten Sie /etc/hosts als root, unter Windows C:\Windows\System32\drivers\etc\hosts in einem als Administrator gestarteten Editor. Zeile ergänzen, mit der IP des neuen Servers:
203.0.113.10 example.com www.example.com
Danach den DNS-Cache leeren, sonst wirkt die Änderung nicht sofort:
resolvectl flush-caches
Unter Windows ipconfig /flushdns, unter macOS sudo dscacheutil -flushcache gefolgt von sudo killall -HUP mDNSResponder. Prüfen, ob es gegriffen hat:
getent hosts example.com
Eine Stolperfalle, die viele Stunden kostet: Firefox mit aktiviertem DNS über HTTPS ignoriert die hosts-Datei. Mozilla hat das ausdrücklich als "wontfix" markiert. Sie sehen dann weiter die alte Seite und halten den Test für gescheitert, obwohl der neue Server längst korrekt antwortet. Deshalb im Testbrowser die verschlüsselte DNS-Auflösung deaktivieren, oder besser: browserunabhängig prüfen. curl kann die Auflösung pro Aufruf überschreiben, ganz ohne hosts-Datei:
curl -sI --resolve example.com:443:203.0.113.10 https://example.com/
Was Sie in diesem Zustand durchgehen sollten: Startseite, mindestens zwei Unterseiten, ein Beitrag mit Bildern, das Login unter /wp-login.php, das Backend, ein Kontaktformular, bei einem Shop ein Testartikel bis zur Kasse. Bilder verdienen besondere Aufmerksamkeit, denn fehlende Uploads fallen im Backend nicht auf.
Was der hosts-Test ausdrücklich nicht abdeckt: alles, was von außen auf den Server zugreift. Zahlungsanbieter-Webhooks, externe Cronjobs, Suchmaschinen-Crawler und Ihr Mailversand landen weiterhin am alten Ziel. Das ist in Ordnung, Sie müssen es nur wissen.
Der Schnitt: Delta-Sync und DNS
Zwischen erstem Kopieren und Umstellung sind Kommentare, Bestellungen oder Beiträge dazugekommen. Die Reihenfolge für einen sauberen Schnitt:
- Auf dem alten Server den Wartungsmodus aktivieren oder zumindest Bestellungen und Kommentare kurz stoppen.
- Dateien erneut synchronisieren, diesmal dauert es Sekunden.
- Datenbank frisch exportieren und auf dem neuen Server importieren.
- Caches leeren:
wp cache flushundwp rewrite flush --hard. - Nochmals per curl gegen die neue IP prüfen.
- A- und AAAA-Record umstellen.
Vergessen Sie den AAAA-Record nicht. Bleibt er auf der alten IPv6-Adresse stehen, landen alle Besucher mit IPv6 weiter auf dem alten Server, während IPv4-Besucher die neue Seite sehen. Das erzeugt genau die Sorte Fehlerbild, bei der zwei Leute nebeneinander sitzen und unterschiedliche Websites sehen.
Den alten Server lassen Sie mindestens eine Woche laufen, ohne Änderungen. Er ist Ihr Rückweg und Ihr Archiv.
Woran Sie erkennen, dass es wirklich gelaufen ist
Nicht "die Seite lädt", sondern messbare Belege:
dig +short A example.com
dig +short AAAA example.com
curl -sI https://example.com/ | head -n 12
Im Header darf kein 301 auf eine alte Domain oder auf http:// stehen. Dann die Datenbank fragen, welche Adresse WordPress selbst für richtig hält:
wp option get siteurl
wp option get home
Ein verlässlicher Test auf übersehene Reste ist ein Suchlauf im Trockenmodus. Meldet er null Ersetzungen, ist die alte Adresse tatsächlich nirgends mehr hinterlegt:
wp search-replace 'alte-domain.de' 'alte-domain.de' --all-tables --dry-run --report-changed-only
Dazu das Zertifikat kontrollieren, inklusive Laufzeit und abgedeckter Namen:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject
Und schließlich das Fehlerlog des Webservers, während Sie fünf Minuten durch die Seite klicken. Wenn dort nichts Neues auftaucht, war es das. Falls doch etwas hängt, ist 502 Bad Gateway beheben die häufigste Anlaufstelle, meist weil der PHP-FPM-Socket im nginx-Block noch die Pfadangabe der alten PHP-Version trägt.
Wenn es schiefgeht: der Rückweg
Der Rückweg besteht aus einem einzigen Handgriff, und deshalb war Schritt 1 so wichtig: A- und AAAA-Record zurück auf die alte IP. Bei einer TTL von 300 Sekunden sind die meisten Besucher innerhalb von fünf Minuten wieder auf dem alten Server, der unverändert weiterlief.
Es gibt genau einen Fall, in dem das nicht sauber ist: wenn auf dem neuen Server bereits Daten entstanden sind, die es auf dem alten nicht gibt. Neue Bestellungen, Kommentare, Registrierungen. Nach einem Rollback existieren diese Daten nur noch im neuen System. Deshalb entscheidet man innerhalb der ersten Minuten oder gar nicht. Und deshalb der Wartungsmodus während des Schnitts: Er hält das Zeitfenster klein, in dem sich beide Datenbestände auseinanderentwickeln können.
Falls Sie doch später zurückmüssen, exportieren Sie vom neuen Server nur die betroffenen Tabellen und spielen sie auf dem alten ein, statt die komplette Datenbank zurückzuschieben. Ein reiner Rollback über eine alte Vollsicherung löscht alles, was in der Zwischenzeit passiert ist.
Fehlermeldungen im Wortlaut
Error establishing a database connection
Zugangsdaten oder DB_HOST in der wp-config.php passen nicht zum neuen Server. Häufig steht dort noch die IP eines externen Datenbankservers statt localhost.
ERROR 1273 (HY000): Unknown collation: 'utf8mb4_0900_ai_ci'
Dump aus MySQL 8 wird in MariaDB importiert. Kollation im Dump per sed auf utf8mb4_unicode_ci setzen.
Error: This does not seem to be a WordPress installation.
WP-CLI wurde im falschen Verzeichnis gestartet oder die Dateien liegen nicht dort, wo Sie vermuten. Mit --path=/var/www/html arbeiten.
ERR_TOO_MANY_REDIRECTS
Fast immer ein Widerspruch zwischen siteurl in der Datenbank, einer Konstante in der wp-config.php und der Weiterleitung im Webserver. Zusätzlich betrifft es Installationen hinter einem Proxy, die den HTTPS-Status nicht mitbekommen und deshalb endlos von http auf https und zurück schicken.
Startseite lädt, alle Unterseiten liefern 404
Der Klassiker beim Wechsel von Apache auf nginx. Die .htaccess mit den Permalink-Regeln wird von nginx ignoriert, dort braucht es try_files $uri $uri/ /index.php?$args; im location-Block.
Die hochgeladene Datei überschreitet die upload_max_filesize-Anweisung in der php.ini.
Die PHP-Konfiguration wurde nicht mit umgezogen. upload_max_filesize, post_max_size und memory_limit auf die Werte des alten Servers setzen.
Weiße Seite, kein Eintrag im Log
Meist ein Drop-in, das ins Leere zeigt: wp-content/object-cache.php oder advanced-cache.php. Umbenennen und neu laden.
Ein Umzug, der so abläuft, hat kein Zeitfenster ohne Website. Der einzige spürbare Moment ist der DNS-Wechsel, und dessen Länge haben Sie zwei Tage vorher selbst festgelegt.
Häufige Fragen
Wie lange dauert es, bis die DNS-Umstellung überall greift?
Warum darf ich die Domain nicht einfach per SQL-Befehl in der Datenbank ersetzen?
Muss ich die Domain überhaupt ersetzen, wenn nur der Server wechselt?
Wie bekomme ich ein Let's-Encrypt-Zertifikat, wenn die Domain noch auf den alten Server zeigt?
Ich habe die hosts-Datei angepasst, sehe aber weiter die alte Seite. Woran liegt das?
Was ist der schnellste Rückweg, wenn nach der Umstellung etwas nicht funktioniert?
2026 KernelHost GmbH. Alle Rechte vorbehalten. Diese Anleitung ist urheberrechtlich geschützt. Eine Veröffentlichung auf anderen Webseiten, auch auszugsweise oder in bearbeiteter Form, ist ohne unsere schriftliche Zustimmung nicht gestattet. Zitate mit Quellenangabe und Link sind ausdrücklich willkommen.

