An einem Nachmittag habe ich einen meiner Blogs aus einer WordPress-Multisite herausgelöst und als eigenständige Installation auf denselben Server gestellt. Am Ende lief die Seite mit eigener Datenbank, eigenem Verzeichnis und gültigem Zertifikat – aber der Weg dorthin führte durch fünf Stolpersteine, von denen ich vier vorher nicht auf dem Zettel hatte.
Dieser Beitrag ist das Protokoll. Kein Tutorial, das so tut, als wäre alles beim ersten Versuch geglückt, sondern der tatsächliche Verlauf mit den Sackgassen: eine ausgesperrte IP-Adresse, ein Zeitlimit, das mir eine Datei zerschossen hat, ein Zertifikat, das sich nicht bewegen wollte, eine Serveroberfläche, die keine Domain anlegen konnte, und eine Cache-Datei aus dem Jahr 2016. Wenn du etwas Ähnliches vorhast, sparst du dir hoffentlich ein paar davon.
Alle Domain-, Server- und Kontonamen sind im Folgenden durch Platzhalter ersetzt. Es geht um das Verfahren, nicht um die konkrete Seite.
Warum überhaupt herauslösen?
Eine WordPress-Multisite ist ein Netzwerk mehrerer Seiten in einer Installation: ein Dateibaum, eine Datenbank, ein gemeinsamer Satz Benutzer. Das ist bequem, solange alle Seiten zusammengehören. Meine tun das nicht mehr. Von den ursprünglichen Netzwerk-Domains lebt nur noch ein Teil, und die Hauptdomain des Netzwerks – nennen wir sie altnetz.example – gehört mir gar nicht mehr.
Das rächt sich im Alltag: Die Netzwerkverwaltung ist nur noch über einen Umweg erreichbar, und die Registrierung neuer Forennutzer lief ins Leere, weil WordPress sie auf die tote Hauptdomain umleitete. Eine einzelne, gesunde Seite in diesem Netzwerk gefangen zu halten, ergibt keinen Sinn. Also: heraus damit, als eigene Installation.
Schritt null: erst ein Backup, dem man trauen kann
Bevor irgendetwas passiert, wird gesichert – der komplette Dateibaum und die gesamte Datenbank. Und hier ging es schon los.
Mein erster Griff war der naheliegende: den Datenbank-Export direkt über die Verbindung streamen. Das lief in ein Zeitlimit von drei Minuten pro Arbeitsschritt und brach mittendrin ab – von 522 Tabellen waren zwei da. Der zweite Versuch war schlauer: die Datei auf dem Server erzeugen und dann herunterladen. Auch das hatte einen Haken.
Für den Download nahm ich rsync mit den Optionen --append-verify --inplace – gedacht, um einen abgebrochenen Transfer fortzusetzen. Das Ergebnis: eine Datei mit exakt der richtigen Größe, aber falscher Prüfsumme. Beim Abbruch mitten im Anhängen war das Ende der Datei inkonsistent, und weil die Größe stimmte, prüfte der nächste Lauf das nicht noch einmal nach. Eine kaputte Sicherung, die aussieht wie eine heile.
Der Weg, der zuverlässig funktionierte:
- das Archiv auf dem Server erzeugen (im Hintergrund, damit es nicht ans Zeitlimit stößt),
- es in Stücke von 300 MB zerlegen,
- jedes Stück in einem sauberen Durchlauf herunterladen und sofort dessen Prüfsumme gegen den Server abgleichen,
- lokal wieder zusammenfügen und die Gesamt-Prüfsumme vergleichen.
Die Lehre daraus ist unbequem, aber eindeutig: Ein Backup ist erst fertig, wenn die Prüfsumme stimmt – nicht, wenn die Dateigröße stimmt. Und --append-verify traut den vorhandenen Bytes zu sehr.
Der Umzug im Prinzip: eine Nummer entfernen
Technisch ist eine Multisite erstaunlich einfach aufgebaut, und genau das macht das Herauslösen möglich. Jede Unterseite hat ihre eigenen Tabellen mit einer Nummer im Namen. Bei der Seite mit der internen Nummer 7 heißen sie wp_7_posts, wp_7_options, wp_7_postmeta und so weiter. Die Hauptseite hat keine Nummer (wp_posts), und ein paar Tabellen sind gemeinsam – vor allem die Benutzer.
Eine Einzelinstallation erwartet die Tabellen ohne diese Nummer. Der Kern des Umzugs ist also: die Tabellen der Seite 7 in eine neue, leere Datenbank übertragen und dabei wp_7_ zu wp_ machen. Klingt nach Suchen-und-Ersetzen – und genau da liegt eine Falle.
Serialisierte Daten. WordPress speichert viele Einstellungen als PHP-serialisierte Zeichenketten, und die enthalten die Länge jedes Textstücks als Zahl. Ein stumpfes Ersetzen quer über den ganzen Export verändert Textlängen und zerbricht damit genau diese Felder. Deshalb habe ich nur die Tabellenbezeichner umbenannt (die stehen sauber abgegrenzt in Anführungszeichen) und die wenigen inhaltlichen Schlüssel – etwa wp_7_capabilities zu wp_capabilities – gezielt per SQL geändert, nicht per Textersetzung über die Datei.
Die Bilder. In der Multisite liegen die Medien einer Unterseite unter uploads/sites/7/, in einer Einzelinstallation direkt unter uploads/. Die Dateien habe ich an die richtige Stelle verschoben; die Verweise darauf im Beitragstext dann mit einem serialisierungssicheren Werkzeug umgeschrieben (/uploads/sites/7 zu /uploads) – also einem, das ein serialisiertes Feld erst entpackt, ersetzt und korrekt wieder zusammensetzt.

Der heikelste Teil sind die Benutzer
Die Benutzer liegen in der gemeinsamen Tabelle wp_users, quer über alle Seiten des Netzwerks. Wer zu welcher Seite gehört, steht nicht dort, sondern in einem Zusatzfeld: Ein Benutzer der Seite 7 hat einen Eintrag wp_7_capabilities. Für die neue Installation wollte ich nur die Mitglieder dieser einen Seite – die Forennutzer inklusive, denn ohne die wäre das Forum eine leere Hülle.
Also: alle Benutzer übernehmen, dann in der neuen Datenbank die aussortieren, die kein wp_capabilities haben, und anschließend die verwaisten Zusatzfelder aufräumen. Die Passwörter bleiben dabei unangetastet – sie sind Hashes und wandern einfach mit. Danach die Kontrollprobe: Gibt es überhaupt noch einen Administrator? Ja, vier. Gut.
Und dann die vier Stolpersteine am Schluss
Der Aufbau der neuen Installation – Dateien kopieren, Datenbank füllen, Konfigurationsdatei ohne die Multisite-Konstanten neu schreiben – lief geradeaus. Ein Probelauf über die Kommandozeile bestätigte: Die Seite bootet, sie sieht sämtliche Beiträge, sie ist keine Multisite mehr. Danach kamen die eigentlichen Überraschungen.

Erstens: Ich habe mich selbst ausgesperrt. Der abgebrochene Streaming-Versuch von vorhin, dazu ein paar Anmeldungen in kurzer Folge – das reichte der Firewall des Servers, um meine IP-Adresse komplett zu blockieren. Nicht nur den Zugang, alle Ports; auch die Website war von meinem Rechner aus plötzlich tot. Von anderer Stelle lief sie weiter, der Server war also gesund. Die Lehre: Ein sauberer Verbindungsabbau und Hintergrundjobs statt langer offener Leitungen ersparen einem diesen Schreck – und die eigene IP gehört auf die Freigabeliste, bevor man einen großen Download startet.
Zweitens: Die Serveroberfläche konnte keine Domain anlegen. Der letzte Schritt eines solchen Umzugs ist, der Domain ein eigenes Verzeichnis zuzuweisen. Das ließ sich weder über die Kommandozeile noch über die grafische Oberfläche erledigen – beide meldeten denselben Fehler: Ein internes Modul der Verwaltungssoftware fehlte auf dem Server (Can't locate …Domains.pm). Die Oberfläche nutzt im Hintergrund dieselben Bausteine wie die Kommandozeile; ist der Baustein kaputt, ist beides betroffen. Das war der Punkt, an dem der Serverbetreiber ins Spiel kam – nur mit Administratorrechten ließ sich die Domain schließlich einrichten.
Drittens: Das Zertifikat wollte nicht. Die frisch angelegte Domain bekam zunächst ein selbstsigniertes Zertifikat – also die Browserwarnung, die jeden Besucher abschreckt. Das gültige, kostenlose Zertifikat lag längst im Konto, ich habe es dem neuen virtuellen Host korrekt zugewiesen, und die Verwaltungssoftware bestätigte das auch. Nur: Der Webserver lieferte hartnäckig weiter das alte, selbstsignierte aus. Er hatte das Zertifikat im Speicher und lud es nicht neu. Ein zweiter Anlauf half nichts – erst ein echter Neustart des Webservers löste es.
Viertens: Eine Leiche von 2016. Als zum Schluss noch der Cache eingerichtet werden sollte, verweigerte das Werkzeug den Dienst: Es fand eine fremde Cache-Datei (advanced-cache.php) und wollte nichts überschreiben. Die Datei stammte von einem Cache-Plugin, das vor Jahren einmal aktiv war, das mitkopiert wurde und das die neue Installation gar nicht mehr nutzte – die zugehörige Schalterstellung war nicht einmal gesetzt, WordPress lud die Datei also nie. Sie lag einfach im Weg. Beiseitegelegt, fertig. Und der Neustart, den das Cache-Werkzeug dabei auslöste, hat gleich auch das Zertifikatsproblem von Punkt drei mit erledigt.
Was am Ende steht
Die Seite läuft jetzt eigenständig auf demselben Server: eigene Datenbank, eigenes Verzeichnis, gültiges Zertifikat, funktionierendes Forum, alle Medien am richtigen Platz, alle Mitglieder übernommen. Die alte Multisite habe ich bewusst unangetastet gelassen – sie ist mein Sicherheitsnetz, solange die neue Installation sich noch einlaufen muss. Erst wenn sie eine Weile stabil steht, wird die Seite dort entfernt.
Wenn du nur ein paar Gedanken aus diesem Bericht mitnimmst, dann diese:
- Prüfsumme statt Dateigröße. Ein Backup ist erst fertig, wenn ein Hash-Vergleich stimmt.
- Serialisierte Daten nie stumpf ersetzen. Tabellennamen ja, Feldinhalte nur mit einem Werkzeug, das die Serialisierung versteht.
- Die gemeinsamen Benutzer sind der wunde Punkt. Wer zu welcher Seite gehört, steckt in einem Zusatzfeld, nicht in der Benutzertabelle.
- Rechne mit der Infrastruktur, nicht nur mit WordPress. Firewall, Serveroberfläche, Webserver-Neustart, ein altes Zertifikat im Speicher – die Hälfte der Sackgassen lag unterhalb von WordPress.
- Halte das Alte, bis das Neue trägt. Ein Rollback, den man nicht braucht, ist billiger als einer, den man nicht hat.
Und der ehrlichste Satz zum Schluss: Der WordPress-Teil war das kleinere Problem. Die Zeit ging für die Umgebung drumherum drauf – für einen Server, der eine Domain nicht anlegen wollte, und einen Webserver, der ein Zertifikat im Speicher festhielt. Das ist die eigentliche Lehre eines solchen Umzugs: Plane die halbe Zeit für das ein, was nicht in WordPress steht.


Schreibe einen Kommentar