Überblick
Das Problem
Ein Serverumzug einer Contao-Website ist Handarbeit, und er besteht aus lauter kleinen Schritten, von denen jeder einzelne die Seite offline halten kann. Datenbank exportieren, per FTP oder SSH übertragen, auf dem neuen Host einspielen, den Dateibaum kopieren, die Zugangsdaten anpassen, die alte Domain aus der Datenbank entfernen — und dann feststellen, dass etwas fehlt.
- Der Dump passt nicht durch. phpMyAdmin bricht beim Import ab, der SQL-Dump ist größer als
post_max_size, und auf vielen Hostings gibt es keine Shell, um es anders zu versuchen. - Die alte Domain steckt überall. Sie steht nicht nur in den Startseiten, sondern in Inhaltselementen, Modulkonfigurationen und in PHP-serialisierten Blobs, in denen ein simples Suchen-und-Ersetzen die Längenangaben zerstört und die Werte unlesbar macht.
- Die Zugangsdaten kippen in die falsche Richtung. Wird die
.env.localder Quelle mitkopiert, zeigt die umgezogene Seite auf die alte Datenbank — im schlimmsten Fall schreibt der neue Host in das noch produktive System. - Verschlüsselte Felder werden unbrauchbar. Ohne den
APP_SECRETder Quelle lassen sich verschlüsselt gespeicherte Datenbankfelder auf dem neuen Host nicht mehr entschlüsseln — das fällt oft erst Wochen später auf. - Die Seite ist da, sieht aber kaputt aus. Auf einer frischen Installation fehlt
public/bundles/, und häufig auch der Web-Zugriff auffiles/— Backend und Frontend laden ohne Stylesheets. - Der Umzug dauert länger als das PHP-Zeitlimit. Jeder Versuch stirbt nach 30 oder 60 Sekunden mittendrin und hinterlässt einen halben Zustand, den niemand sicher beurteilen kann.
Am härtesten trifft es Agenturen, die regelmäßig Kundenseiten zwischen Hostern bewegen, und Betreiber auf verwalteten Plattformen ohne Shell-Zugang: Dort ist jeder dieser Schritte entweder gar nicht oder nur über Umwege durchführbar, und ein abgebrochener Umzug bedeutet Ausfallzeit auf einer produktiven Seite.
Die Lösung
Das Grundprinzip in einem Satz: Der Migrator verpackt Datenbank, Dateien und Geheimnisse einer Contao-5-Installation in ein signiertes, in Stücke zerlegtes .tcmig-Paket, das er auf dem Zielhost in wiederaufnehmbaren Zeitscheiben wieder auspackt — komplett aus dem Contao-Backend heraus, ohne Shell.
Strukturell ändert sich dadurch vor allem eines: Der Umzug ist kein einzelner, langer Vorgang mehr, der gelingen oder scheitern kann, sondern ein Auftrag aus benannten Schritten mit gespeichertem Fortschritt. Jeder Schritt schreibt seinen Stand auf die Platte, bevor das Zeitbudget abläuft; ein abgebrochener Request kostet höchstens die gerade laufende Scheibe. Ein minütlicher Cron bringt den Auftrag auch dann voran, wenn niemand im Backend zusieht.
| Aufgabe | Manueller Umzug | Mit dem Contao Migrator |
|---|---|---|
| Datenbank übertragen | Dump erzeugen, herunterladen, hochladen, per phpMyAdmin einspielen — bei großen Datenbanken Glückssache | Tabellen werden in gzip-komprimierte INSERT-Stücke zerlegt (Standard 2000 Zeilen je Stück) und einzeln eingespielt |
| Dateien übertragen | FTP über Stunden, ohne verlässliche Aussage, ob alles angekommen ist | tar.gz-Stücke von je 50 MiB, jedes mit SHA-256 im Manifest geprüft |
| Alte Domain ersetzen | Suchen-und-Ersetzen im SQL-Dump — zerstört serialisierte Daten | Vorprüfung findet die betroffenen Spalten; die Ersetzung erhält die s:LEN:-Präfixe serialisierter Werte |
| Zugangsdaten des neuen Hosts | Nach dem Kopieren von Hand nachziehen und hoffen, nichts übersehen zu haben | DATABASE_URL, TRUSTED_PROXIES, TRUSTED_HOSTS werden vor dem Auspacken gesichert und danach wieder eingesetzt |
| Verschlüsselungs-Schlüssel | Manuell aus der alten .env.local übernehmen | APP_SECRET und die Encryption-Keys reisen passphrase-verschlüsselt mit |
| Laufzeit | Ein Request, der am Zeitlimit stirbt | Zeitbudget je Scheibe (Standard 20 s), Wiederaufnahme über Browser-Schleife oder Cron |
| Zwei Server ohne Zwischenstopp | Nicht vorgesehen | Direkte Übertragung von Server zu Server mit Einmal-Kopplungstoken (Pro) |
Den Problemen von oben stehen damit konkrete Mechanismen gegenüber: der Vorprüfung (Speicherplatz, URL-Kandidaten, composer.json-Audit), dem Paket mit Manifest und Prüfsummen, der serialisierungssicheren Host-Umschreibung, dem Konfigurationsabgleich aus Ziel-Snapshot und mitgeführten Geheimnissen, der automatischen Nachbereitung (assets:install, Cache leeren, files/ im Web-Root verfügbar machen) und dem eigenständigen Wiederherstellungs-Panel für den Fall, dass das Backend nach einem Umzug nicht mehr lädt.
Wann das Paket passt
| Situation | Einschätzung |
|---|---|
| Contao-5.3-Seite zieht auf einen anderen Hoster um | Genau dafür gebaut. Export auf der Quelle, Import auf dem Ziel, beides aus dem Backend. |
Kein SSH-Zugang, kein mysqldump, kein Shell-Zugriff | Passt. Alles läuft im PHP-Prozess der Website; auch contao:migrate und assets:install werden in-process ausgeführt. |
Große Datenbank oder großer files/-Baum, strenge Upload-Limits | Passt. Download und Import lassen sich in Teildateien zerlegen; der Server-zu-Server-Push verkleinert seine Stücke automatisch, wenn das Ziel mit HTTP 413 antwortet. |
| Kopie einer Live-Seite als Staging-System aufsetzen | Passt, mit der Einschränkung, dass der Import die Zieldatenbank vollständig ersetzt — siehe Import. |
| Regelmäßige, automatische Sicherung der Seite | Nicht dieses Paket. Es gibt keine Zeitsteuerung und keine Backup-Rotation im Sinne eines Backup-Werkzeugs; Exporte werden vom Betreiber ausgelöst, und ältere Backup-Verzeichnisse werden nach retention_backups (Standard 3) gelöscht. |
| Upgrade von Contao 4 auf Contao 5 im Zuge des Umzugs | Nicht dieses Paket. Der Migrator ist ausdrücklich ein Umzug, kein Upgrade: Das Ziel soll am Ende exakt die Versionen der Quelle fahren. Ein Versionsunterschied führt zu einer Kompatibilitätswarnung, die bestätigt werden muss. |
| Nur einzelne Seitenbäume oder einzelne Tabellen übernehmen | Nicht dieses Paket. Ein Paket enthält die ganze Installation; es gibt keine Auswahl auf Tabellen- oder Seitenebene. |
Teil 1 — Einrichtung
Der Weg von der Installation bis zum fertigen Umzug, in dieser Reihenfolge:
- Voraussetzungen prüfen — PHP-, Contao- und Rechteanforderungen.
- Vor der Installation — Sicherung, Entscheidungen, Testumgebung.
- Installation über den Contao Manager — der übliche Weg.
- Installation über Composer — die Alternative mit Shell-Zugang.
- Installation überprüfen — woran Sie erkennen, dass es geklappt hat.
- Lizenz aktivieren — ohne gültige Lizenz bleibt das Modul gesperrt.
- Konfiguration — nur nötig, wenn die Standardwerte nicht passen.
- Der erste Umzug — der kürzeste vollständige Weg.
Voraussetzungen
| Anforderung | Version / Wert | Anmerkung |
|---|---|---|
| PHP | ^8.2 | Muss auf Quelle und Ziel erfüllt sein. |
| Contao | contao/core-bundle ^5.3 | Contao 4 wird nicht unterstützt. |
| PHP-Erweiterungen | ext-json, ext-zlib | zlib wird für die gzip-Stücke gebraucht. |
| Symfony | ^6.4 oder ^7.0 | Config, DI, HttpFoundation, HttpKernel. |
| Doctrine DBAL | ^3.6 oder ^4.0 | Die Speicherplatz-Schätzung nutzt information_schema, also MySQL/MariaDB. |
| Contao-Manager-Plugin | ^2.0 | Ausdrücklicher Konflikt mit <2.0 und >=3.0. |
| Lizenz | Trial, Free oder Pro | Pro Domain über v-t.one. Ohne gültige, signierte Lizenz zeigt das Modul nur den Hinweis auf die Einstellungen. |
Schreibrechte braucht der Migrator an diesen Stellen:
| Pfad | Wofür |
|---|---|
var/migrator/ | Arbeitsverzeichnis: Aufträge, Backups, Staging, Snapshots, Token, Lizenzzustand. Wird bei Bedarf angelegt. |
public/ | Beim Start der Anwendung wird _tcmig-recovery.php dorthin gespiegelt (Vergleich per MD5, also nur bei Änderung). |
.env.local (Ziel) | Der Konfigurationsabgleich schreibt die Datei nach dem Import neu (Modus 0640). |
| Projektwurzel (Ziel) | Der Import legt den Dateibaum der Quelle über das Ziel. |
var/cache/ (Ziel) | Wird in der Nachbereitung geleert. |
Der Migrator legt keine eigenen Datenbanktabellen an. Aufträge, Konfiguration und Lizenzzustand liegen als Dateien unter var/migrator/. Der einzige Eingriff in die Datenbankstruktur ist ein reines Anzeigefeld in den Contao-Einstellungen, das selbst nichts speichert.
Vor der Installation
Der Migrator wird auf beiden Installationen gebraucht: auf der Quelle für den Export, auf dem Ziel für den Import. Planen Sie deshalb beide Seiten gemeinsam.
- Vollständige Sicherung des Ziels. Der Import ersetzt auf dem Ziel jede Tabelle, die im Paket enthalten ist, und legt den Dateibaum der Quelle darüber. Was dort vorher stand, ist danach weg.
- Passphrase festlegen und notieren. Sie brauchen dieselbe Zeichenfolge später auf dem Ziel. Warum sie praktisch verpflichtend ist, steht unter Export.
- Freien Speicherplatz prüfen. Die Vorprüfung verlangt das Doppelte aus geschätzter Datenbankgröße plus Dateibaum und bricht sonst sofort ab.
- Zugangsdaten des Ziels bereithalten. Existiert auf dem Ziel noch keine
DATABASE_URL, kommentiert der Abgleich den Wert der Quelle aus — Sie müssen den neuen Wert dann selbst eintragen. - Domain der Startseite auf dem Ziel setzen. Die Lizenzaktivierung bindet an eine konfigurierte Domain; ohne Domain in einer Startseite ist keine Aktivierung möglich.
- Wenn möglich zuerst auf einem Testsystem üben. Ein Import auf einer leeren Contao-5-Installation zeigt den vollständigen Ablauf ohne Risiko.
Installation über den Contao Manager
- Contao Manager öffnen und anmelden.
- Bereich Entdecken öffnen. Neue Pakete werden immer dort gesucht und hinzugefügt; der Bereich Pakete daneben zeigt unter Installierte Pakete nur, was bereits vorhanden ist. Entdecken ist zugleich die Startansicht.
- Über Pakete suchen nach
vtinnovations/migratorsuchen und beim Treffer Paket hinzufügen wählen. - Änderungen anwenden. Der Contao Manager installiert das Paket und aktualisiert den Autoloader.
- Bereich Systemwartung → Datenbank-Migrationen und -Backups → Datenbank prüfen; die angezeigten Datenbank-Änderungen bestätigen. Der Migrator selbst bringt keine Tabellen mit, der Schritt gehört aber zum sauberen Abschluss jeder Installation.
- Unter Systemwartung den Anwendungs-Cache leeren (in der Navigation auch als Cache erneuern).
Diese Schritte auf beiden Installationen ausführen — auf der Quelle und auf dem Ziel.
Installation über Composer
composer require vtinnovations/migrator
Auf einer Managed Edition anschließend:
vendor/bin/contao-console contao:setup
vendor/bin/contao-console cache:clear
Aktualisieren:
composer update vtinnovations/migrator
vendor/bin/contao-console cache:clear
Das Paket nicht als ZIP über vendor/ entpacken. Die Registrierung läuft über das Contao-Manager-Plugin aus der composer.json (extra.contao-manager-plugin). Wird der Ordner von Hand kopiert, ohne dass Composer den Autoloader und die Plugin-Liste neu schreibt, lädt das Bundle nicht — und das Backend-Modul erscheint nicht.
Installation überprüfen
- Im Contao-Backend erscheint in der Navigation die Gruppe Contao Migrator mit dem Eintrag Contao Migrator („Diese Contao-Seite auf einen neuen Host umziehen — exportieren, importieren oder direkt an eine gekoppelte Installation senden.“).
- Ohne aktive Lizenz zeigt das Modul nur die Karte Lizenz erforderlich mit der Schaltfläche Einstellungen öffnen. Das ist der erwartete Zustand direkt nach der Installation.
- In den Contao-Einstellungen gibt es jetzt die Legende V-T.ONE Licence management mit dem Abschnitt Migrator.
- Mit Shell-Zugang lässt sich die Registrierung der Routen prüfen:
vendor/bin/contao-console debug:router | grep tcmig
Erwartet werden unter anderem tcmig_status, tcmig_tick, tcmig_download sowie die beiden öffentlichen Endpunkte tcmig_ingest_chunk und tcmig_ingest_finalize.
Lizenz aktivieren
Die Lizenzverwaltung liegt an genau einer Stelle: Contao → Einstellungen, Legende V-T.ONE Licence management, Abschnitt Migrator. Das Backend-Modul selbst nimmt nie einen Schlüssel entgegen, es verweist nur dorthin.
So aktivieren Sie die Lizenz
- Stellen Sie sicher, dass mindestens eine Contao-Startseite eine Domain eingetragen hat. Fehlt sie, meldet der Abschnitt: „Keine Domain auf dieser Instanz konfiguriert — trage zuerst die Domain der Startseite ein.“
- Öffnen Sie Contao → Einstellungen und scrollen Sie zur Legende V-T.ONE Licence management, Abschnitt Migrator.
- Solange nichts aktiviert ist, steht dort Nicht lizenziert und darunter der Hinweis „Gib unten deinen V-T.ONE-Lizenzschlüssel ein und speichere, um den Migrator auf dieser Instanz freizuschalten.“ Zusätzlich werden unter Konfigurierte Hosts die Domains angezeigt, an die gebunden werden kann.
- Tragen Sie den Schlüssel in das Feld Lizenzschlüssel ein (Platzhalter
XXXXX-XXXXX-XXXXX-XXXXX). - Klicken Sie auf Lizenz prüfen & aktivieren. Die Schaltfläche sendet das Einstellungsformular ab; es ist kein zusätzliches Speichern nötig.
- Warten Sie die Antwort ab: Die Prüfung läuft synchron gegen den Lizenzdienst von V-T.ONE, das Formular kehrt erst danach zurück. Bei Erfolg meldet Contao „Lizenz aktiviert.“
- Der Statusblock zeigt anschließend eine der Zeilen Testlizenz aktiv, Free-Lizenz aktiv oder Pro-Lizenz aktiv, dazu Schlüssel (maskiert), Paket, Gültig ab, Gültig bis und Zuletzt geprüft sowie unter Enthalten die freigeschalteten Fähigkeiten.
- Öffnen Sie danach das Modul Contao Migrator: Statt der Lizenzkarte erscheinen jetzt die vier Reiter.
| Schaltfläche | Wirkung |
|---|---|
| Lizenz prüfen & aktivieren | Prüft den eingegebenen Schlüssel gegen v-t.one und speichert den signierten Zustand. Meldung bei Erfolg: „Lizenz aktiviert.“ |
| Lizenz aktualisieren | Erneuert den gespeicherten Zustand mit dem bereits hinterlegten Schlüssel; das Eingabefeld wird dabei nicht gelesen. Meldung: „Lizenz aktualisiert.“ Ohne gespeicherten Zustand: „Es ist keine Lizenz zum Aktualisieren gespeichert.“ |
| Lizenz entfernen | Fragt „Lizenz entfernen und den Migrator auf dieser Instanz deaktivieren?“ und setzt die Instanz danach auf den unlizenzierten Zustand zurück. Meldung: „Lizenz entfernt.“ |
Die Bindung erfolgt auf exakte Hosts. Aktiviert werden kann nur, wenn mindestens ein normalisierter Host aus den Startseiten exakt in der signierten Domainliste vorkommt. Es gibt keine Gleichsetzung von example.tld und www.example.tld, keine Platzhalter und keine Vererbung auf Subdomains. Schlägt es fehl, meldet Contao „Die Lizenz konnte für diese Instanz nicht aktiviert werden.“
Nach dem Umzug ist das Ziel eine eigene Instanz. Der Lizenzzustand ist an die jeweilige Installation gebunden und wird nicht mit dem Paket übertragen. Aktivieren Sie die Lizenz auf dem Zielhost deshalb separat, bevor Sie dort importieren.
Konfiguration
Der Migrator läuft ohne jede Konfiguration. Es gibt zwei Ebenen, falls die Standardwerte nicht passen.
Container-Konfiguration (config/config.yaml)
vtinnovations_migrator:
scratch_dir: '%kernel.project_dir%/var/migrator'
time_budget: 20.0
| Schlüssel | Standard | Bedeutung |
|---|---|---|
scratch_dir | %kernel.project_dir%/var/migrator | Arbeitsverzeichnis für Aufträge, Backups und Staging. Relative Pfade werden gegen das Projektverzeichnis aufgelöst. |
time_budget | 20.0 | Sekunden, die eine einzelne Scheibe rechnen darf, bevor gespeichert und abgegeben wird. |
Laufzeitwerte (var/migrator/config.json)
Diese Datei wird vom Paket nur gelesen, nie geschrieben — es gibt keine Oberfläche dafür. Wenn Sie einen Wert ändern wollen, legen Sie die Datei selbst an; fehlende Schlüssel fallen auf den Standard zurück.
{
"archive_chunk_bytes": 52428800,
"download_volume_bytes": 83886080,
"db_rows_per_chunk": 2000
}
| Schlüssel | Standard | Bedeutung |
|---|---|---|
excludes | vendor, var/cache, var/log, var/migrator, node_modules, .git, .github, assets/vendor | Pfade, die nicht ins Dateiarchiv wandern (Präfixvergleich auf den projektrelativen Pfad). |
archive_chunk_bytes | 52428800 (50 MiB) | Zielgröße eines files.NNN.tar.gz-Stücks. |
push_chunk_bytes | 4194304 (4 MiB) | Startgröße eines Push-Stücks bei der Server-zu-Server-Übertragung. Bei HTTP 413 halbiert sich der Wert automatisch bis auf 64 KiB. |
db_rows_per_chunk | 2000 | Zeilen je INSERT-Stückdatei. |
db_max_insert_bytes | 1048576 (1 MiB) | Obergrenze für ein einzelnes INSERT-Statement, damit max_allowed_packet nicht überschritten wird. |
retention_backups | 3 | Wie viele Backup-Verzeichnisse nach einem Export aufgehoben werden; ältere werden gelöscht. |
download_volume_bytes | 83886080 (80 MiB) | Teilgröße, die verwendet wird, wenn beim Download keine eigene Größe angegeben wird. |
mailer_policy | keep | keep: Das Ziel behält seine eigene MAILER_DSN. Jeder andere Wert bewirkt, dass sie nicht gesichert wird und der Wert der Quelle stehen bleibt. |
Zwei Standardwerte haben derzeit keine Wirkung. preserve_destination_admins und allowed_peers stehen zwar in der Standardkonfiguration, werden aber an keiner Stelle im Code ausgewertet. Verlassen Sie sich nicht darauf: Administratorkonten des Ziels werden beim Import nicht geschont, und der Zugang zu den Ingest-Endpunkten wird ausschließlich über den Einmal-Kopplungstoken geregelt, nicht über eine Hostliste.
Der erste Umzug
Der kürzeste vollständige Weg für einen manuellen Umzug (Modus A). Er funktioniert mit jeder Lizenzstufe.
- Auf dem Ziel: Contao 5.3 installieren, den Migrator installieren und die Lizenz aktivieren.
- Auf der Quelle: Modul Contao Migrator öffnen, Reiter Export, eine Passphrase eintragen, Export starten.
- Den Auftrag durchlaufen lassen und mögliche Rückfragen beantworten (siehe Pausen und Bestätigungen).
- Nach abgeschlossen über Paket herunterladen die
.tcmig-Datei sichern — bei großen Paketen über Teildateien. - Auf dem Ziel: Reiter Import, Paketdatei wählen, dieselbe Passphrase eintragen, Hochladen & importieren.
- Die Kompatibilitätswarnung bestätigen, falls eine erscheint, und anschließend Alter Host / Neuer Host eintragen und Umschreibung anwenden.
- Nach Abschluss die Hinweise im Auftragsprotokoll umsetzen — im Regelfall
composer install --no-devauf dem Ziel; siehe Nachbereitung am Ziel. - Frontend und Backend prüfen, danach die DNS-Einträge umstellen.
Teil 2 — Funktionen im Detail
Das Modul Contao Migrator hat vier Reiter: Export, Import, Server‑zu‑Server und Wiederherstellung. Oberhalb der Reiter zeigt ein Monitor den aktiven Auftrag, darunter steht die Liste Aufträge.
Export: Paket erstellen
Der Export baut aus der laufenden Installation ein portables .tcmig-Paket. Er liegt im Reiter Export, beschrieben mit „Ein portables .tcmig-Paket dieser Website erstellen und herunterladen.“ Der Export gehört zum Free-Funktionsumfang.
So erstellen Sie ein Paket
- Backend → Contao Migrator → Reiter Export.
- Im Feld Export-Passphrase eine Passphrase eintragen. Die Oberfläche bezeichnet sie als „(optional — verschlüsselt Geheimnisse & signiert das Paket)“; für einen Umzug auf einen anderen Host ist sie in der Praxis erforderlich — siehe Warnung unten.
- Export starten klicken. Der Auftrag wird angelegt, die Seite springt auf den Monitor.
- Den Fortschritt verfolgen. Der Monitor zeigt Fortschrittsbalken, aktuellen Schritt und die letzten Protokollzeilen; die Schritte heißen Vorprüfung, Datenbank-Dump, Dateien archivieren, Geheimnisse, Export abschließen.
- Falls der Auftrag bei „composer.json muss vor Versand geprüft werden“ pausiert: entscheiden Sie zwischen Fürs Migrations-Paket beheben (vendor/ mitschicken + portable composer.json) und Trotzdem fortfahren. Details unter Pausen und Bestätigungen.
- Warten, bis der Status abgeschlossen lautet und das Protokoll „Export abgeschlossen — Paket bereit zum Download.“ meldet.
- Die Schaltfläche Paket herunterladen erscheint im Monitor. Das Paket kann auch später aus der Auftragsliste geladen werden.
Ohne Passphrase lässt sich das Paket auf einem anderen Host nicht einspielen. Wird keine Passphrase gesetzt, signiert der Export das Manifest mit dem Operator-Token dieser Installation (var/migrator/auth.token). Dieses Token liegt im Arbeitsverzeichnis, das vom Archiv ausgeschlossen ist, und existiert auf dem Ziel nicht. Die Prüfung beim Import schlägt dann mit „Manifest-Signatur ungültig — manipuliertes Paket.“ fehl, und der Auftrag bricht ab. Ein Paket ohne Passphrase ist also nur auf derselben Installation wieder einspielbar. Setzen Sie für jeden echten Umzug eine Passphrase und notieren Sie sie.
Ohne Passphrase reisen auch keine Geheimnisse mit. APP_SECRET, CONTAO_ENCRYPTION_KEY und DATABASE_ENCRYPTION_KEY werden nur dann verschlüsselt mitgegeben, wenn eine Passphrase gesetzt ist. Sonst protokolliert der Schritt „Secrets-Schritt: nichts verschlüsselt (Ziel muss Geheimnisse neu eingeben).“ — und verschlüsselte Datenbankfelder sind auf dem Ziel nicht mehr lesbar.
Was der Export tut:
| Schritt | Was passiert |
|---|---|
| Vorprüfung | Erfasst Umgebung (PHP, Contao, Symfony, installierte Pakete, Erweiterungen, Limits), liest die Hosts aller Startseiten, schätzt den Speicherbedarf und durchsucht die Datenbank nach Spalten, die den Quell-Host enthalten. Auch das composer.json-Audit läuft hier. |
| Datenbank-Dump | Schema einmal, danach je Tabelle gzip-komprimierte INSERT-Stücke unter db/data/{tabelle}.{NNN}.sql.gz. Wiederaufnehmbar je Tabelle und Position. |
| Dateien archivieren | Der Projektbaum ohne die ausgeschlossenen Pfade, gestückelt in files/files.{NNN}.tar.gz. Beim Weg „Fürs Migrations-Paket beheben“ wandert zusätzlich vendor/ mit. |
| Geheimnisse | Verschlüsselt die drei Schlüssel nach secrets/secrets.enc (Dateirechte 0600), sofern eine Passphrase vorliegt. |
| Export abschließen | Signiert das Manifest, schreibt checksums.json, meldet das Paket als herunterladbar und löscht Backup-Verzeichnisse jenseits von retention_backups. |
Der Browser-Tab darf zu sein. Bei geöffnetem Monitor treibt der Browser den Auftrag in einer Dauerschleife voran; ist der Tab geschlossen, übernimmt der minütliche Cron. Mit offenem Tab ist der Auftrag erheblich schneller fertig.
Download und geteilter Download
Das Paket wird nicht als zusätzliche Datei auf der Platte erzeugt, sondern beim Abruf aus dem Backup-Verzeichnis gestreamt. Der Dateiname folgt dem Muster contao-migration-<8 Zeichen der Auftrags-ID>.tcmig.
So laden Sie ein großes Paket in Teilen herunter
- Im Monitor des abgeschlossenen Auftrags erscheint neben Paket herunterladen das Feld Max. MB pro Teil (Vorgabe 10).
- Die gewünschte Teilgröße eintragen — sinnvoll ist ein Wert unterhalb von
upload_max_filesizeundpost_max_sizedes Zielhosts, denn dort müssen die Teile wieder hochgeladen werden. - Teile vorbereiten klicken. Angezeigt wird die Anzahl der Teile, die Gesamtgröße und je Teil ein Link Teil n/m.
- Entweder die Teile einzeln anklicken oder Alle nacheinander laden verwenden; die Downloads werden dabei mit kurzem Abstand gestartet, damit der Browser keinen verwirft.
- Passt das Paket in eine Datei, meldet die Oberfläche „Paket passt in eine Datei — nutze Download oben.“
- Alle Teildateien im selben Ordner behalten. Sie heißen
….tcmig.001,….tcmig.002und so fort — die Reihenfolge ist für den Import entscheidend.
In der Auftragsliste steht bei jedem fertigen Export zusätzlich die Schaltfläche Teile, die dieselben Teil-Links mit der Standardgröße von 80 MiB auflistet.
Import: Paket einspielen
Der Import liegt im Reiter Import: „Ein .tcmig-Paket hochladen und auf dieser Website wiederherstellen.“ Auch er gehört zum Free-Funktionsumfang.
Der Import ist zerstörend. Die Wiederherstellung der Datenbank löscht jede im Paket enthaltene Tabelle auf dem Ziel und legt sie neu an (DROP + CREATE); anschließend wird der Dateibaum der Quelle über das Ziel gelegt, einschließlich .env.local und config/. Gesichert wird vom Migrator nur eine Kopie von .env und .env.local unter var/migrator/snapshots/ — kein Datenbank-Backup des Ziels. Legen Sie dieses vorher selbst an.
So spielen Sie ein Paket ein
- Auf dem Zielhost anmelden und das Modul Contao Migrator öffnen, Reiter Import.
- Unter Paketdatei „(einzelne .tcmig)“ die Paketdatei wählen.
- Unter Passphrase „(falls das Paket mit einer Passphrase signiert wurde)“ dieselbe Passphrase eintragen, die beim Export verwendet wurde.
- Hochladen & importieren klicken. Der Upload läuft in einem Request — schlägt er an den Serverlimits fehl, nehmen Sie den geteilten Import.
- Den Monitor beobachten. Die Schritte heißen Paket entpacken, Paket verifizieren, Kompatibilitätsprüfung, Ziel-Konfig erfassen, Sicherungs-Snapshot, Dateien extrahieren, Datenbank wiederherstellen, URLs ersetzen, Konfig abgleichen, Nachbearbeitung, Import abschließen.
- Erscheint eine Kompatibilitätswarnung, prüfen und mit Trotzdem fortfahren bestätigen.
- Bei der Pause zur Host-Umschreibung Alter Host und Neuer Host eintragen und Umschreibung anwenden klicken.
- Warten, bis das Protokoll „Migrations-Import abgeschlossen. Seite prüfen, dann „contao:migrate“ ausführen.“ zeigt — und dann die Hinweise unter Nachbereitung am Ziel lesen, bevor Sie
contao:migratetatsächlich ausführen.
Geteilter Import
Für Pakete, die als Ganzes nicht durch das Upload-Limit passen. Die Oberfläche fragt im selben Reiter: „Paket zu groß für einen einzelnen Upload? Teile den Download unten in kleine Teile, wähle sie dann hier alle aus — sie werden nacheinander hochgeladen.“
So laden Sie ein Paket in Teilen hoch
- Voraussetzung: Sie haben das Paket auf der Quelle über Teile vorbereiten in Teildateien geladen.
- Im Reiter Import unter Alle Teile auf einmal wählen (.001, .002, …) im Dateidialog sämtliche Teildateien markieren.
- Die Passphrase in das darunterliegende Feld eintragen.
- Hochladen & importieren klicken. Die Teile werden nach Dateinamen sortiert und einzeln nacheinander hochgeladen; die Fortschrittszeile zeigt „Lade Teil 3/7 (…)“.
- Das Browserfenster muss während des Uploads geöffnet bleiben — der Upload wird vom Browser gesteuert, nicht vom Server. Beim Schließen bricht er ab und muss neu begonnen werden.
- Nach dem letzten Teil meldet die Oberfläche „Füge Teile zusammen & starte Import…“ und springt in den Monitor des neuen Import-Auftrags.
- Ab hier verläuft alles wie beim normalen Import.
Die Reihenfolge zählt. Die Teile werden in Namensreihenfolge aneinandergehängt. Fehlt ein Teil oder ist die Reihenfolge falsch, meldet der Zusammenbau „Zusammengeführtes Paket: Prüfsummen-Fehler (beschädigte oder manipulierte Übertragung).“ oder der Auftrag scheitert später an einem Prüfsummen-Fehler.
Server-zu-Server-Übertragung
Die direkte Übertragung ohne manuelles Herunterladen und Hochladen. Sie liegt im Reiter Server‑zu‑Server und erfordert eine Pro-Lizenz auf beiden Seiten — auf der sendenden wie auf der empfangenden Installation. Mit einer Free-Lizenz zeigt der Reiter die Karte In dieser Lizenz nicht enthalten und stellt keine Bedienelemente dar; ein selbst gebauter POST wird ebenfalls abgewiesen.
Die Rollen: Eine Installation ist das ZIEL (neuer Host, empfängt), die andere die QUELLE (alter Host, sendet). Der Migrator läuft auf beiden.
So übertragen Sie direkt von Server zu Server
- Am ZIEL: Reiter Server‑zu‑Server öffnen, Karte Empfangen „(Modus B — ZIEL)“, Kopplungstoken erzeugen klicken.
- Der Token erscheint sofort darüber, mit dem Hinweis „Kopplungstoken (gültig bis HH:MM UTC) — füge ihn in der QUELL-Installation ein. Er wird nur einmal angezeigt:“. Jetzt kopieren — er wird nicht erneut angezeigt. Die Form ist
session.key, die Gültigkeit beträgt zunächst eine Stunde und verlängert sich mit jedem angenommenen Stück der laufenden Übertragung. - An der QUELLE: Reiter Server‑zu‑Server, Karte Senden „(Modus B — QUELLE)“.
- Basis-URL des Ziels eintragen, zum Beispiel
https://new-host.tld— die Wurzel-URL der Zielinstallation, ohne Pfad. - Den Kopplungstoken einfügen.
- Eine Passphrase setzen; das Feld ist dort ausdrücklich mit „(erforderlich, damit das Ziel das Paket verifizieren kann)“ beschriftet. Notieren Sie sie — Sie brauchen sie gleich noch am Ziel.
- Erstellen & senden klicken. Die Quelle baut zuerst ein vollständiges Paket (dieselben fünf Export-Schritte) und schickt es danach in HMAC-signierten Stücken an das Ziel; die zusätzlichen Schritte heißen Paket bauen und Paket senden.
- Nach dem letzten Stück legt das Ziel automatisch einen Import-Auftrag an; das Protokoll der Quelle meldet „Übertragung abgeschlossen — Remote-Import-Auftrag <ID>.“
- Am ZIEL das Modul öffnen: Der Import-Auftrag steht auf pausiert und verlangt „Dieses Paket ist mit einer Passphrase signiert. Gib die Export-Passphrase ein, um es zu verifizieren und fortzufahren.“ Passphrase eintragen und Verifizieren & fortfahren klicken.
- Den Import am Ziel wie gewohnt zu Ende führen — inklusive Kompatibilitätsbestätigung und Host-Umschreibung.
Was der Push mit Größenlimits macht. Er beginnt mit 4-MiB-Stücken. Antwortet das Ziel mit HTTP 413, halbiert die Quelle das Stück und wiederholt dieselbe Position — bis hinunter zu 64 KiB. Erst wenn auch das abgelehnt wird, scheitert der Auftrag mit „Ziel hat selbst einen 64 KiB-Chunk abgelehnt (HTTP 413). Erhöhe am Ziel-Webserver client_max_body_size / post_max_size.“ Der Fortschritt wird nach jedem angekommenen Stück gespeichert, eine unterbrochene Übertragung setzt an der Byte-Position fort.
Pausen und Bestätigungen
Ein Auftrag hält an vier Stellen an und wartet auf eine Entscheidung. Solange er auf pausiert steht, treibt ihn weder Browser noch Cron voran — er wartet ausschließlich auf Sie. Die Bedienelemente erscheinen unterhalb des Monitors.
1. composer.json-Audit (vor dem Export, einmalig)
Meldung: „composer.json-Probleme, die die Installation am Ziel stören könnten — vor dem Versand prüfen:“, darunter die einzelnen Befunde.
| Befund | Bedeutung |
|---|---|
| Lokales PATH-Repository | „Repository „…“ ist ein lokales PATH-Repo (…) — der Ziel-Host hat dieses Verzeichnis nicht, daher schlägt composer install fehl, sofern das Paket nicht veröffentlicht ist oder derselbe Pfad dort existiert.“ |
| VCS-Repository | „… ist ein …-Repo (…) — das Ziel braucht Netzwerkzugang und Zugangsdaten, um es beim composer install zu erreichen.“ |
| Eigenes composer-Repository | „… stelle sicher, dass es am Ziel-Host erreichbar und authentifiziert ist.“ |
| Packagist deaktiviert | „… alle Abhängigkeiten müssen aus den eigenen Repositories kommen, die am Ziel-Host erreichbar sein müssen.“ |
| dev-Version gefordert | „… dev-Versionen sind nicht reproduzierbar, sofern das Quell-Repo am Ziel nicht erreichbar ist.“ |
minimum-stability nicht stable | „… das Ziel könnte andere, instabile Versionen auflösen als die Quelle.“ |
PATH-Paket ohne version | „… composer install könnte es am Ziel ablehnen (Path-Pakete sollten eine Version pinnen).“ |
composer.json fehlt / ungültiges JSON | „composer.json im Projekt-Root nicht gefunden …“ bzw. „… ist kein gültiges JSON — vor der Migration korrigieren.“ |
Zwei Antworten stehen zur Wahl:
- Fürs Migrations-Paket beheben (vendor/ mitschicken + portable composer.json) — der Export nimmt zusätzlich den gesamten
vendor/-Baum auf und legt eine portablecomposer.jsonals Override ins Paket. Das Paket wird deutlich größer, dafür braucht das Ziel keincomposer install. - Trotzdem fortfahren — es wird nichts geändert; die Verantwortung für die Auflösbarkeit auf dem Ziel liegt bei Ihnen.
2. Passphrase fehlt oder ist falsch (beim Import)
Meldung: „Dieses Paket ist mit einer Passphrase signiert. Gib die Export-Passphrase ein, um es zu verifizieren und fortzufahren.“ Eingabefeld Export-Passphrase, Schaltfläche Verifizieren & fortfahren. Bei einer falschen Eingabe pausiert der Auftrag erneut mit „Manifest-Signatur ungültig — falsche Passphrase. Export-Passphrase erneut eingeben.“ Diese Pause ist beliebig oft wiederholbar; es geht dabei nichts verloren.
3. Kompatibilitätswarnung (beim Import)
Meldung: „Kompatibilitätswarnungen:“ mit den betroffenen Punkten, dann Trotzdem fortfahren. Geprüft wird genau zweierlei:
- PHP-Downgrade — das Ziel hat eine ältere PHP-Version als die Quelle.
- Unterschiedliche Contao-Hauptversion zwischen Quelle und Ziel.
4. Host-Umschreibung (beim Import)
Meldung: „Bestätige die Host-Umschreibung, bevor die Datenbank umgeschrieben wird:“ mit den Feldern Alter Host (Platzhalter old-domain.tld) und Neuer Host (new-domain.tld) und der Schaltfläche Umschreibung anwenden. Details im nächsten Abschnitt.
Host-Umschreibung
Schon beim Export durchsucht die Vorprüfung alle Textspalten der Datenbank nach den Hosts der Startseiten und merkt sich im Manifest, welche Tabelle und welche Spalte betroffen ist — und ob die Werte PHP-serialisiert sind. Beim Import werden genau diese Spalten umgeschrieben.
So schreiben Sie die Domain um
- Der Import pausiert beim Schritt URLs ersetzen, sobald Kandidaten gefunden wurden.
- Unter Alter Host die bisherige Domain eintragen, genau so, wie sie in der Datenbank steht (ohne Protokoll, zum Beispiel
alt.example.tld). - Unter Neuer Host die künftige Domain eintragen.
- Umschreibung anwenden klicken. Der Auftrag läuft weiter und meldet am Ende „URL-Umschreibung fertig (N Wert(e) geändert).“
- Sind beide Felder leer oder identisch, wird nichts geändert: Der Schritt meldet dann „Host-Zuordnung ohne Wirkung — nichts umzuschreiben.“ und der Import läuft trotzdem zu Ende.
Serialisierte Werte bleiben gültig. Die Ersetzung läuft über einen serialisierungssicheren Ersetzer, der die Längenpräfixe (s:LEN:) mitkorrigiert. Genau hier scheitert ein Suchen-und-Ersetzen im SQL-Dump. Tabellen mit Primärschlüssel werden per Keyset durchlaufen, sodass ein abgebrochener Request mitten in der Tabelle fortsetzen kann; Tabellen ohne Primärschlüssel werden in einem Durchgang über ihre eindeutigen Werte verarbeitet.
Es lässt sich pro Auftrag genau ein Host-Paar eintragen. Hatte die Installation mehrere Domains, bleiben die übrigen unverändert und müssen nachträglich von Hand korrigiert werden.
Geheimnisse und .env-Abgleich
Beim Umzug treffen zwei gegenläufige Anforderungen aufeinander: Die Datenbank-Zugangsdaten müssen die des neuen Hosts bleiben, die Verschlüsselungs-Schlüssel dagegen müssen die der alten Installation sein. Der Migrator trennt das an zwei Stellen im Ablauf.
| Schlüssel | Herkunft nach dem Import |
|---|---|
DATABASE_URL, TRUSTED_PROXIES, TRUSTED_HOSTS | Vom Ziel. Vor dem Auspacken gesichert, danach wieder eingesetzt. |
MAILER_DSN | Vom Ziel, solange mailer_policy auf keep steht (Standard). |
APP_SECRET, CONTAO_ENCRYPTION_KEY, DATABASE_ENCRYPTION_KEY | Von der Quelle, entschlüsselt aus dem Paket — Voraussetzung dafür, dass verschlüsselte Datenbankfelder lesbar bleiben. |
Vor allem Zerstörerischen sichert der Schritt Sicherungs-Snapshot die Dateien .env und .env.local des Ziels nach var/migrator/snapshots/<8 Zeichen der Auftrags-ID>/ (Dateirechte 0600). Das ist bewusst kein Datenbank-Backup: Es ist die Versicherung dagegen, sich mit falschen Datenbank-Koordinaten selbst auszusperren.
Hatte das Ziel keine eigene DATABASE_URL, müssen Sie sie selbst eintragen. Der Abgleich kommentiert den mitgelieferten Wert der Quelle in der .env.local aus, damit die umgezogene Seite nicht gegen die Datenbank der Quelle startet. Im Protokoll steht dann ein Hinweis mit den betroffenen Schlüsseln, und die Zeile selbst trägt den Vermerk # neutralized by migrator — set this to the NEW host value. Die Seite läuft erst, wenn Sie dort die Zugangsdaten des neuen Hosts eintragen.
Nachbereitung am Ziel
Der Schritt Nachbearbeitung läuft automatisch und erledigt drei Dinge im Prozess der Website — ohne Shell, was auf gesperrten Hostings der entscheidende Punkt ist:
- Bundle-Assets neu veröffentlichen (
assets:install --symlink --relative):public/bundles/existiert auf einem frischen Ziel nicht und wird nicht mitarchiviert; ohne diesen Schritt laufen alle Bundle-Stylesheets ins Leere und Backend wie Frontend erscheinen ungestylt. - Upload-Verzeichnis im Web-Root verfügbar machen: Existiert
public/filesnicht, wird ein relativer Symlink angelegt; wo das Dateisystem keine Symlinks erlaubt, wird der Baum kopiert. - Cache leeren:
var/cachewird geleert, damit der nächste Aufruf den Container gegen die abgeglichene.env.localneu baut.
Danach bleibt eine Aufgabe bei Ihnen, und sie hängt davon ab, ob vendor/ im Paket lag:
| Paket | Protokollzeile | Was zu tun ist |
|---|---|---|
ohne vendor/ (Normalfall) | „Reiner Umzug: führe am Ziel „composer install --no-dev“ aus, damit Contao + Erweiterungen den Quell-Versionen aus der migrierten composer.lock entsprechen (inkl. Downgrades). contao:migrate NICHT ausführen — die wiederhergestellte Datenbank passt bereits zum Quell-Schema.“ | composer install --no-dev auf dem Ziel ausführen — über Shell oder über den Contao Manager. |
mit vendor/ (Weg „Fürs Migrations-Paket beheben“) | „vendor/ wurde mit dem Paket mitgeschickt — KEIN „composer install“ nötig; das Ziel läuft mit exakt dem Quellcode und den Versionen der Quelle.“ | Nichts. Gegebenenfalls wurde zusätzlich eine portable composer.json angewendet. |
Zu contao:migrate stehen im Protokoll zwei gegenläufige Sätze. Die Nachbearbeitung rät ausdrücklich davon ab („contao:migrate NICHT ausführen“), der abschließende Schritt Import abschließen meldet dagegen „Migrations-Import abgeschlossen. Seite prüfen, dann „contao:migrate“ ausführen.“ Beide Zeilen stammen aus dem Code und widersprechen einander. Die belastbare Regel: Bei einem reinen Umzug, bei dem das Ziel nach composer install exakt dieselben Versionen fährt wie die Quelle, ist contao:migrate nicht nötig und kann Tabellen einer Version anlegen, von der Sie gerade herunterstufen. Nötig wird es erst, wenn das Ziel bewusst eine neuere Contao-Version behält — dann ist es der Weg, das Schema nachzuziehen; genau dafür gibt es die Schaltfläche im Wiederherstellungs-Panel.
Läuft assets:install nicht durch, steht im Protokoll der Ersatzweg: „assets:install konnte nicht automatisch laufen — führe „vendor/bin/contao-console assets:install --symlink --relative public“ manuell aus, sonst bleibt Backend/Frontend ungestylt.“
Aufträge verwalten
Unter den Reitern steht die Liste Aufträge mit den zwölf jüngsten Einträgen und den Spalten ID, Typ, Status, Fortschritt und Aktion. Ist noch nichts gelaufen, steht dort „Noch keine Aufträge.“
| Status | Bedeutung |
|---|---|
| ausstehend | Angelegt, aber noch keine Scheibe gelaufen. |
| läuft | Wird gerade vorangetrieben. |
| pausiert | Wartet auf eine Eingabe von Ihnen. Weder Browser noch Cron bringen ihn weiter. |
| abgeschlossen | Alle Schritte fertig. |
| fehlgeschlagen | Abgebrochen; der Grund steht in der Statuszeile und im Protokoll. |
| abgebrochen | Vom Betreiber abgebrochen. |
So brechen Sie einen Auftrag ab oder löschen ihn
- Für einen laufenden Auftrag in der Zeile auf Abbrechen klicken (im Monitor gibt es dieselbe Schaltfläche).
- Die Rückfrage „Diesen Auftrag abbrechen?“ bestätigen. Der Abbruch greift innerhalb der laufenden Scheibe, nicht erst danach.
- Ein abgeschlossener, fehlgeschlagener oder abgebrochener Auftrag zeigt stattdessen Löschen.
- Die Rückfrage „Diesen Auftrag samt Paket/Backup löschen? Kann nicht rückgängig gemacht werden.“ bestätigen. Damit verschwinden auch das Paket und das zugehörige Backup-Verzeichnis.
- Ein noch aktiver Auftrag lässt sich nicht löschen; der Versuch wird mit „Brich den Auftrag ab, bevor du ihn löschst.“ abgewiesen.
Ein Abbruch während des Imports hinterlässt einen Zwischenzustand. Wurde die Datenbank bereits teilweise wiederhergestellt oder der Dateibaum teilweise ausgepackt, ist das Ziel danach weder alt noch neu. Es gibt keine automatische Rücknahme — spielen Sie in diesem Fall Ihr eigenes Backup zurück oder lassen Sie den Import vollständig durchlaufen.
Wiederherstellungs-Panel
Das eigenständige Panel ist eine einzelne Datei im Web-Root, die das Bundle bei jedem Start der Anwendung dorthin spiegelt: public/_tcmig-recovery.php. Sie läuft unabhängig vom Contao-Backend und rendert eigenes, minimales HTML — deshalb funktioniert sie auch dann noch, wenn das Backend selbst nicht mehr lädt, etwa weil nach einer versionsübergreifenden Wiederherstellung eine Tabelle fehlt. Das Panel gehört zum Free-Funktionsumfang.
So öffnen Sie das Panel
- Solange das Backend läuft: Modul Contao Migrator → Reiter Wiederherstellung → Eigenständiges Wiederherstellungs-Panel öffnen →. Der Link enthält den Operator-Token bereits, das Panel öffnet sich in einem neuen Tab.
- Notieren Sie sich vorher den darunter angezeigten Wiederherstellungs-Token. Die Oberfläche weist darauf hin, dass er auch in
var/migrator/auth.tokensteht und „nötig wenn das Backend nicht erreichbar ist“. - Wenn das Backend nicht mehr lädt:
https://ihre-domain.tld/_tcmig-recovery.phpaufrufen, den Token ausvar/migrator/auth.tokenin das Feld Operator-Token eintragen und Wiederherstellungs-Panel öffnen klicken. - Existiert noch kein Token, meldet die Anmeldeseite: „Es existiert noch kein Operator-Token. Starte einmal einen Export oder Import im Backend, damit die Token-Datei erstellt wird, und komm dann hierher zurück.“
So treiben Sie einen hängenden Auftrag voran
- Das Panel zeigt oben Status, Schritt und Fortschritt des jüngsten Auftrags sowie das Protokoll.
- Aktiven Auftrag antreiben klicken. Die Schaltfläche ruft wiederholt eine Zeitscheibe auf, bis der Auftrag endet.
- Verlangt der Auftrag eine Passphrase, erscheint das Feld Export-Passphrase mit Verifizieren & fortfahren — dieselbe Funktion wie im Backend.
- Liegen
composer.json-Warnungen vor, erscheinen hier ebenfalls Fürs Paket beheben und Trotzdem fortfahren. - Mit Auftrag abbrechen lässt sich ein laufender Auftrag beenden (Rückfrage „Diesen Auftrag abbrechen?“).
- Der Tab muss offen bleiben: Antreiben und Migrieren laufen synchron im Request; ein geschlossener Tab bricht die gerade laufende Scheibe ab.
So reparieren Sie ein Backend, das nach der Wiederherstellung nicht mehr lädt
- Panel öffnen (Token-Anmeldung, siehe oben).
- contao:migrate ausführen klicken. Das Panel erklärt selbst, was passiert: Der Befehl „repariert das Datenbank-Schema (erstellt Tabellen, die ein neueres Contao nach einer versionsübergreifenden Wiederherstellung erwartet) UND veröffentlicht die Bundle-Web-Assets neu (erstellt public/bundles/ neu — behebt ein ungestyltes Backend/Frontend nach frischer Wiederherstellung)“.
- Warten. Beides läuft ohne Shell im Prozess; bei Erfolg meldet das Panel „contao:migrate fertig (Exit 0). Backend neu laden.“
- Kommt keine JSON-Antwort zurück („Migrate fehlgeschlagen — HTTP … (kein JSON). Siehe Log.“ oder „(leere Antwort — vermutlich PHP-Timeout oder Speicherlimit)“), reichen Zeit- oder Speicherlimit des Hosts nicht aus; dann führen Sie den Befehl über die Shell aus.
- Backend neu laden.
Der Token steht in der URL. Der Aufruf aus dem Backend hängt den Operator-Token als Query-Parameter an, und Query-Strings landen in Server-Logs. Das Panel ist ein Notfallwerkzeug — wenn das stört, löschen Sie danach var/migrator/auth.token; beim nächsten Zugriff wird ein neuer Token erzeugt. Eine Schaltfläche zum Wechseln des Tokens gibt es nicht.
Auch das Panel ist lizenzgebunden — und es fällt geschlossen aus. Kann der Kernel nicht starten, bleibt es lesbar, aber alle Aktionen sind deaktiviert; angezeigt wird dann der Hinweis „Dieses Plugin ist gesperrt. …“ Mit einer Free-Lizenz sind Antreiben, Migrieren und Abbrechen verfügbar, Kopplungstoken erzeugen bleibt deaktiviert.
Lizenzstufen: Free und Pro
Der Migrator kennt genau zwei Fähigkeiten, und der Statusblock in den Einstellungen zeigt sie unter Enthalten mit Haken oder Strich an.
| Fähigkeit | Umfasst | Trial | Free | Pro |
|---|---|---|---|---|
| Export, Import & Wiederherstellung | Paket erstellen, herunterladen (auch geteilt), hochladen und einspielen, Aufträge verwalten, Wiederherstellungs-Panel | ✓ | ✓ | ✓ |
| Server-zu-Server-Übertragung | Kopplungstoken erzeugen, Paket direkt senden, Paket direkt empfangen | ✓ | — | ✓ |
Praktisch heißt das: Mit einer Free-Lizenz können Sie eine Website vollständig umziehen — exportieren, das Paket herunterladen, auf dem Ziel hochladen und einspielen. Was fehlt, ist allein der Verzicht auf den Zwischenschritt über Ihren Rechner. Der gesperrte Reiter sagt das auch so: „Die direkte Server-zu-Server-Übertragung erfordert eine Pro-Lizenz. Exportiere stattdessen ein .tcmig-Paket und importiere es auf dem Ziel — dieser Weg ist in jeder Lizenz enthalten. Für eine direkte Übertragung benötigen sowohl die sendende als auch die empfangende Installation die Pro-Fähigkeit.“
| Statuszeile | Bedeutung |
|---|---|
| Nicht lizenziert | Kein gültiger Zustand gespeichert. Das Modul zeigt nur den Verweis auf die Einstellungen. |
| Testlizenz aktiv | Trial — enthält auch die Server-zu-Server-Übertragung, damit die kostenpflichtige Fähigkeit geprüft werden kann. |
| Free-Lizenz aktiv | Export, Import und Wiederherstellung. |
| Pro-Lizenz aktiv | Voller Umfang. |
| Pro-Lizenz abgelaufen — Free-Funktionsumfang aktiv | Abgelaufene Pro-Lizenz, deren Paket den Free-Rückfall erlaubt: Export, Import und Wiederherstellung laufen weiter, die direkte Übertragung nicht. |
| Lizenz abgelaufen | Abgelaufen ohne Rückfall — das Modul ist gesperrt. |
| Lizenz kann auf dieser Installation nicht geprüft werden | Der gespeicherte Zustand besteht die Prüfung nicht, etwa weil die Datei verändert wurde. |
Ein Auftrag behält seine Stufe. Die benötigte Fähigkeit wird aus den Daten des Auftrags abgeleitet und an jeder Grenze erneut geprüft — im Backend, im Cron und im Wiederherstellungs-Panel. Läuft eine Pro-Lizenz mitten in einer Übertragung ab, wird der Auftrag nur nicht mehr vorangetrieben; er wird weder gelöscht noch als fehlgeschlagen markiert und läuft weiter, sobald die Fähigkeit wieder vorhanden ist. Ein Export auf der Free-Stufe läuft unbeeindruckt weiter.
Teil 3 — Für Entwickler
Job-Pipeline und Schritte
Ein Auftrag ist eine geordnete Liste benannter Schritte mit einem Cursor. Der Runner führt den Schritt am Cursor so lange aus, bis er complete meldet, und speichert nach jeder Scheibe. Rückgabewerte eines Schritts sind COMPLETE, CONTINUE (derselbe Schritt erneut), PAUSE und FAIL.
| Auftragstyp | Schrittfolge |
|---|---|
| Export (Modus A) | preflight → dump_database → archive_files → secrets → finalize_export |
| Push (Modus B, Quelle) | wie Export, danach build_package → push_package |
| Import (A und B) | unpack_package → verify_package → compat_gate → capture_dest_config → safety_snapshot → extract_files → restore_database → url_replace → config_reconcile → post_migration → finalize_import |
Der Fortschritt ist cursor / Anzahl Schritte — also eine Schrittzählung, keine Zeit- oder Byteschätzung. Das Protokoll eines Auftrags ist auf 500 Einträge begrenzt; die Schritte protokollieren in Englisch, die Übersetzung passiert erst bei der Anzeige anhand der Sprache, die beim Anlegen des Auftrags aktiv war.
Routen
| Name | Methode und Pfad | Zugang |
|---|---|---|
tcmig_status | GET /contao/migrator/status/{id} | Backend-Firewall. Nur lesend; treibt den Auftrag bewusst nicht voran. |
tcmig_tick | GET /contao/migrator/tick/{id} | Backend-Firewall. Eine Zeitscheibe je Aufruf. |
tcmig_download | GET /contao/migrator/download/{id} | Backend-Firewall. ?meta=1 liefert Größe und Teileanzahl, ?part=N&vol=MB einen Byte-Ausschnitt. |
tcmig_upload_part | POST /contao/migrator/upload-part/{isess} | Backend-Firewall, CSRF-geprüft. |
tcmig_assemble | POST /contao/migrator/assemble/{isess} | Backend-Firewall, CSRF-geprüft. |
tcmig_cancel | POST /contao/migrator/cancel/{id} | Backend-Firewall, CSRF-geprüft. |
tcmig_delete | POST /contao/migrator/delete/{id} | Backend-Firewall, CSRF-geprüft. |
tcmig_ingest_chunk | POST /migrator/ingest/{session} | Öffentlich, authentifiziert per HMAC über den Einmal-Kopplungsschlüssel. Verlangt die Pro-Fähigkeit auf dem Ziel. |
tcmig_ingest_finalize | POST /migrator/ingest/{session}/finalize | Wie oben; legt den Import-Auftrag an und verbraucht die Kopplung. |
Die Signaturen der Übertragung: je Stück HMAC(key, "{session}|{index}|{sha256(body)}") im Header X-Tcmig-Signature zusammen mit X-Tcmig-Index; beim Abschluss HMAC(key, "{session}|finalize|{count}|{sha256(gesamt)}") mit X-Tcmig-Count und X-Tcmig-Sha.
Die Lizenzverwaltung besitzt keine eigene Route — sie läuft vollständig über Contaos eigenes Einstellungsformular. Suchen Sie also keinen Endpunkt dafür.
Container-Konfiguration
Konfigurierbar sind genau zwei Container-Parameter:
| Parameter | Wert |
|---|---|
vtinnovations_migrator.scratch_dir | Standard %kernel.project_dir%/var/migrator |
vtinnovations_migrator.time_budget | Standard 20.0 |
Weitere Parameter setzt die Erweiterung als feste Code-Konstanten. Sie sind bewusst nicht über die Konfiguration änderbar und für den Betrieb ohne Belang.
Das Bundle wird über Vtinnovations\Migrator\ContaoManager\Plugin registriert und nach ContaoCoreBundle geladen; dasselbe Plugin lädt die Routendatei. Eine eigene Monolog-Konfiguration bringt das Paket nicht mit: Der Runner protokolliert über den Standard-Logger der Anwendung, der eigentliche Auftragsverlauf liegt in der Auftragsdatei.
Dateien und Verzeichnisse
| Pfad | Inhalt |
|---|---|
var/migrator/jobs/<id>.json | Der Auftrag: Schritte, Cursor, Metadaten, Protokoll. |
var/migrator/jobs/<id>.secret | Transiente Passphrase (0600). Wird beim Abschluss des Exports beziehungsweise des Imports gelöscht und steht nie in der Auftragsdatei. |
var/migrator/jobs/<id>.cancel | Abbruchmarkierung, sperrfrei geschrieben, damit ein Abbruch auch während einer laufenden Scheibe greift. |
var/migrator/backups/<id>/ | Das erzeugte Paket vor dem Zusammenpacken: Manifest, DB-Stücke, Datei-Stücke, secrets/, checksums.json, gegebenenfalls overrides/. |
var/migrator/staging/<id>/ | Das entpackte Paket beim Import; wird am Ende gelöscht. |
var/migrator/snapshots/<id8>/ | .env und .env.local des Ziels vor dem Import. |
var/migrator/incoming/<session>/ | Hochgeladene Pakete und Teildateien. |
var/migrator/config.json | Laufzeitwerte. Wird nur gelesen. |
var/migrator/auth.token | Operator-Token (0600) für das Wiederherstellungs-Panel; Signaturschlüssel für Pakete ohne Passphrase. |
var/migrator/pairings.json | Offene Kopplungen (0600); verbrauchte und abgelaufene werden entfernt. |
weitere Dateien in var/migrator/ | Interner, an diese Installation gebundener Lizenzzustand. Nicht bearbeiten und nicht auf eine andere Installation kopieren — eine veränderte Datei gilt als ungültig, nicht als lizenziert. |
public/_tcmig-recovery.php | Das Wiederherstellungs-Panel; wird beim Start der Anwendung gespiegelt. |
Das gesamte Verzeichnis var/migrator steht in der Ausschlussliste des Archivs und gehört nicht in die Versionsverwaltung.
Cron und Zeitbudget
Das Paket registriert einen Contao-Cronjob im Intervall minutely, der jeden nicht abgeschlossenen und nicht pausierten Auftrag um eine Zeitscheibe voranbringt. Eine Auftragssperre verhindert Kollisionen zwischen Cron und Browser-Schleife: Wer die Sperre hält, arbeitet; der andere tritt zurück.
Contaos Web-Cron wird nur durch Frontend-Zugriffe ausgelöst — bei einem reinen Backend-Umzug entstehen die unter Umständen gar nicht. Für verlässlichen Fortschritt bei geschlossenem Tab richten Sie einen Systemcron ein:
* * * * * php vendor/bin/contao-console contao:cron
Der Endpunkt tcmig_tick gibt die PHP-Session vor der Arbeit frei und hebt das Zeitlimit auf, damit die schnellen Statusabfragen nicht hinter einer langen Scheibe warten müssen.
Paketformat .tcmig
Eine .tcmig-Datei ist das gepackte Backup-Verzeichnis eines Auftrags:
| Eintrag | Inhalt |
|---|---|
manifest.json | Umgebung, Startseiten-Hosts, URL-Kandidaten, Speicherschätzung, Tabellen- und Datei-Stücke mit SHA-256, Signaturverfahren, Signatur. |
db/schema.sql | Das Schema aller Tabellen. |
db/data/{tabelle}.{NNN}.sql.gz | Die Daten als gzip-komprimierte INSERT-Stücke. |
files/files.{NNN}.tar.gz | Der Projektbaum ohne die ausgeschlossenen Pfade. |
secrets/secrets.enc | Die verschlüsselten Geheimnisse — nur vorhanden, wenn eine Passphrase gesetzt war. |
overrides/composer.json | Die portable composer.json — nur beim Weg „Fürs Migrations-Paket beheben“. |
checksums.json | Prüfsummen von Manifest, Tabellen und Datei-Stücken. |
Signiert wird das Manifest per HMAC-SHA-256: mit einem aus der Passphrase abgeleiteten Schlüssel, sonst mit dem Operator-Token der erzeugenden Installation. Das Feld signedWith im Manifest sagt, welches von beiden gilt — und ist der Grund, warum ein Paket ohne Passphrase auf einem fremden Host nicht verifizierbar ist.
Ausgehende Verbindungen
| Ziel | Wann | Inhalt |
|---|---|---|
| Lizenzdienst von V-T.ONE | Beim Aktivieren und Aktualisieren der Lizenz | Der Lizenzschlüssel und die gewählte konfigurierte Domain. Die Antwort wird signiert geprüft, bevor sie gespeichert wird. |
| V-T.ONE | Beim Öffnen des Backend-Moduls | Ein Aufrufsignal mit Produktname und Domain; bei gültiger Lizenz einmal je angemeldeter Sitzung zusätzlich ein Signal zur Lizenzbestätigung. Der Versand erfolgt erst nach der Auslieferung der Seite, mit kurzem Zeitlimit; Fehler bleiben ohne Folgen für Anzeige und Lizenz. |
| Basis-URL des Ziels | Beim Server-zu-Server-Push | Die Paketstücke an /migrator/ingest/…. TLS-Prüfung aktiv; bis zu drei Weiterleitungen werden als POST gefolgt, damit ein erzwungener kanonischer Host die Übertragung nicht abbricht. |
Erweiterungspunkte
Bewusst deutlich, weil es Supportaufwand spart: Dieses Paket bietet keine Erweiterungspunkte. Konkret gibt es
- keine Contao-Hooks und keine eigenen Events,
- keine eigenen Konsolenbefehle — der Migrator ruft lediglich
contao:migrateundassets:installim Prozess auf, - keine Frontend-Module und keine Inhaltselemente,
- keine eigenen Datenbanktabellen und keine Modelle,
- keine Oberfläche für
config.json— Laufzeitwerte werden ausschließlich auf der Platte geändert.
Erweiterbar ist die Pipeline technisch über zusätzliche Dienste, die StepInterface implementieren und automatisch registriert werden; die Schrittlisten der Auftragstypen sind allerdings Konstanten im Paket, sodass ein eigener Schritt ohne Änderung am Paket in keiner Auftragsfolge auftaucht.
Fehlerbehebung
| Symptom | Ursache und Prüfung |
|---|---|
| Das Modul zeigt nur „Dieses Plugin benötigt eine Lizenz. Aktiviere sie unter Contao → Einstellungen, um alle Funktionen freizuschalten.“ | Keine gültige, signierte Lizenz auf dieser Instanz. Über Contao → Einstellungen → V-T.ONE Licence management → Migrator aktivieren. |
| „Keine Domain auf dieser Instanz konfiguriert — trage zuerst die Domain der Startseite ein.“ | Keine Startseite hat eine Domain. Die Aktivierung bindet an eine konfigurierte Domain und kann ohne sie nicht stattfinden. |
| „Die Lizenz konnte für diese Instanz nicht aktiviert werden.“ | Die signierten Domains der Lizenz und die konfigurierten Hosts überschneiden sich nicht exakt. example.tld und www.example.tld gelten als verschiedene Hosts. |
| Der Reiter Server‑zu‑Server zeigt „In dieser Lizenz nicht enthalten“ | Free-Lizenz. Export und Import stehen weiterhin zur Verfügung; für die direkte Übertragung brauchen beide Seiten Pro. |
| Der Export bricht sofort ab: „Nicht genügend Speicherplatz: benötige ~N MiB, M MiB frei.“ | Die Vorprüfung verlangt das Doppelte aus Datenbankgröße und Dateibaum. Platz schaffen oder Ausschlüsse in config.json erweitern. |
| Der Export pausiert mit „composer.json muss vor Versand geprüft werden — N Warnung(en).“ | Kein Fehler, sondern das Audit. Entweder Fürs Migrations-Paket beheben oder Trotzdem fortfahren. |
| Der Import pausiert mit „Dieses Paket ist passphrase-signiert — Export-Passphrase zur Verifizierung angeben.“ | Erwartetes Verhalten. Passphrase des Exports eintragen und Verifizieren & fortfahren klicken. |
| „Manifest-Signatur ungültig — falsche Passphrase. Export-Passphrase erneut eingeben.“ | Tippfehler oder falsche Passphrase. Beliebig oft wiederholbar, es geht nichts verloren. |
| „Manifest-Signatur ungültig — manipuliertes Paket.“ und der Auftrag schlägt fehl | Das Paket wurde ohne Passphrase erstellt und wird auf einer anderen Installation eingespielt: Es ist mit dem Operator-Token der Quelle signiert, das dem Ziel nicht vorliegt. Export mit Passphrase wiederholen. |
| „Prüfsummen-Fehler: …“ oder „Fehlender Chunk: …“ | Unvollständiger oder beschädigter Upload. Teildateien vollzählig und in Reihenfolge (.001, .002, …) hochladen. |
| „Zusammengeführtes Paket: Prüfsummen-Fehler (beschädigte oder manipulierte Übertragung).“ | Beim geteilten Import fehlte ein Teil oder die Reihenfolge stimmte nicht. Vorgang mit allen Teilen wiederholen. |
| Der Upload der Paketdatei bricht ohne Fehlermeldung ab | post_max_size oder upload_max_filesize des Ziels sind kleiner als das Paket. Den geteilten Import verwenden. |
| „Ziel hat selbst einen 64 KiB-Chunk abgelehnt (HTTP 413). …“ | Der Zielserver begrenzt die Body-Größe zu strikt. client_max_body_size (nginx) beziehungsweise post_max_size am Ziel erhöhen. |
| Der Push scheitert mit „Push rejected by destination: Unknown, expired or consumed pairing.“ | Der Kopplungstoken ist abgelaufen (eine Stunde ab Erzeugung), wurde bereits verbraucht oder gehört zu einer anderen Zielinstallation. Am Ziel einen neuen Token erzeugen. Die Ingest-Endpunkte antworten in Englisch. |
| Der Auftrag steht auf pausiert und bewegt sich nicht mehr | Eine Pause wartet immer auf eine Eingabe — sie wird weder vom Cron noch vom Browser aufgelöst. Die Bedienelemente stehen unterhalb des Monitors; sind sie nicht erreichbar, weil das Backend nicht lädt, hilft das Wiederherstellungs-Panel. |
| Der Auftrag steht auf ausstehend und kommt bei geschlossenem Tab nicht voran | Contaos Web-Cron wird nur durch Frontend-Zugriffe ausgelöst. Systemcron auf contao:cron einrichten oder das Backend-Fenster offen lassen. |
| Backend und Frontend erscheinen nach dem Import ohne Stylesheets | public/bundles/ und/oder der Web-Zugriff auf files/ fehlen. Das Protokoll nennt den Ersatzweg; alternativ im Wiederherstellungs-Panel contao:migrate ausführen, das die Assets mit veröffentlicht. |
| Die umgezogene Seite zeigt Inhalte des alten Servers oder startet nicht | In der .env.local steht noch der auskommentierte Wert der Quelle mit dem Vermerk # neutralized by migrator. Die Zugangsdaten des neuen Hosts eintragen. |
| Verschlüsselte Datenbankfelder sind nach dem Umzug unlesbar | Der Export lief ohne Passphrase, deshalb wurden APP_SECRET und die Encryption-Keys nicht mitgegeben. Werte aus der alten .env.local von Hand übernehmen. |
| Nach dem Umzug fehlen Tabellen oder das Backend wirft einen Datenbankfehler | Das Ziel fährt eine neuere Contao-Version als das Paket. Entweder per composer install --no-dev auf die Versionen der Quelle zurückgehen oder im Wiederherstellungs-Panel contao:migrate ausführen; siehe Nachbereitung am Ziel. |
| Das Wiederherstellungs-Panel meldet „Es existiert noch kein Operator-Token. …“ | Die Token-Datei entsteht erst beim ersten lizenzierten Zugriff auf das Backend-Modul. Modul einmal öffnen, dann erneut versuchen. |
| Im Panel sind alle Schaltflächen deaktiviert | Der Kernel lässt sich nicht starten oder es liegt keine gültige Lizenz vor. Das Panel fällt bewusst geschlossen aus und bleibt nur lesbar. |
| Das Modul erscheint gar nicht in der Backend-Navigation | Das Bundle ist nicht registriert (Installation ohne Composer) oder die Benutzergruppe hat kein Recht auf das Backend-Modul. |
Bekannte Einschränkungen
- Ein Paket ist immer die ganze Installation. Es gibt keine Auswahl einzelner Tabellen, Seitenbäume oder Verzeichnisse.
- Der Import ist nicht zurücknehmbar. Gesichert werden nur
.envund.env.localdes Ziels. Ein Datenbank-Backup des Ziels müssen Sie selbst anlegen. - Pro Auftrag lässt sich genau ein Host-Paar umschreiben. Mehrsprachige Installationen mit mehreren Domains brauchen Nacharbeit.
- Administratorkonten des Ziels werden nicht geschont. Die Datenbank der Quelle ersetzt die des Ziels vollständig; melden Sie sich nach dem Import mit den Zugangsdaten der Quelle an.
- Ohne Passphrase kein Umzug auf einen anderen Host. Siehe Export.
- Keine Zeitsteuerung. Exporte und Importe werden von Hand gestartet; der Cron treibt nur bereits angelegte Aufträge voran.
- Der Operator-Token kann nicht über die Oberfläche gewechselt werden. Löschen Sie
var/migrator/auth.token, um einen neuen zu erzwingen — Pakete, die ohne Passphrase mit dem alten Token signiert wurden, sind danach nicht mehr verifizierbar. - Die Speicherplatz-Schätzung setzt MySQL oder MariaDB voraus. Auf anderen Systemen wird der Datenbankanteil mit 0 angesetzt.
- Die Lizenzprüfung braucht ausgehende HTTPS-Verbindungen zu
www.v-t.one. In abgeschotteten Netzen ist keine Aktivierung möglich. - Der Fortschrittsbalken zählt Schritte, nicht Bytes. Bei großen Datenbanken steht er deshalb lange auf demselben Wert, obwohl der Auftrag arbeitet — das Protokoll ist der verlässlichere Indikator.
Deinstallation
- Alle Aufträge abschließen oder abbrechen. Ein laufender Auftrag schreibt sonst in ein Verzeichnis, das gleich verschwindet.
- Im Abschnitt Migrator der Contao-Einstellungen auf Lizenz entfernen klicken und die Rückfrage bestätigen, damit der Lizenzplatz wieder frei wird.
- Das Paket entfernen — im Contao Manager unter Pakete, oder per Composer:
composer remove vtinnovations/migrator vendor/bin/contao-console cache:clear - Das Arbeitsverzeichnis
var/migrator/löschen. Es enthält Pakete, Backups, Snapshots, den Operator-Token und den Lizenzzustand und wird beim Entfernen des Pakets nicht mit gelöscht. - Die Datei
public/_tcmig-recovery.phplöschen. Sie bleibt sonst im Web-Root liegen; ohne Bundle ist sie funktionslos, gehört aber trotzdem entfernt. - Datenbankseitig ist nichts aufzuräumen — das Paket hat keine eigenen Tabellen angelegt.
