Ü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.local der 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_SECRET der 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 auf files/ — 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.

AufgabeManueller UmzugMit dem Contao Migrator
Datenbank übertragenDump erzeugen, herunterladen, hochladen, per phpMyAdmin einspielen — bei großen Datenbanken GlückssacheTabellen werden in gzip-komprimierte INSERT-Stücke zerlegt (Standard 2000 Zeilen je Stück) und einzeln eingespielt
Dateien übertragenFTP über Stunden, ohne verlässliche Aussage, ob alles angekommen isttar.gz-Stücke von je 50 MiB, jedes mit SHA-256 im Manifest geprüft
Alte Domain ersetzenSuchen-und-Ersetzen im SQL-Dump — zerstört serialisierte DatenVorprüfung findet die betroffenen Spalten; die Ersetzung erhält die s:LEN:-Präfixe serialisierter Werte
Zugangsdaten des neuen HostsNach dem Kopieren von Hand nachziehen und hoffen, nichts übersehen zu habenDATABASE_URL, TRUSTED_PROXIES, TRUSTED_HOSTS werden vor dem Auspacken gesichert und danach wieder eingesetzt
Verschlüsselungs-SchlüsselManuell aus der alten .env.local übernehmenAPP_SECRET und die Encryption-Keys reisen passphrase-verschlüsselt mit
LaufzeitEin Request, der am Zeitlimit stirbtZeitbudget je Scheibe (Standard 20 s), Wiederaufnahme über Browser-Schleife oder Cron
Zwei Server ohne ZwischenstoppNicht vorgesehenDirekte Ü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

SituationEinschätzung
Contao-5.3-Seite zieht auf einen anderen Hoster umGenau dafür gebaut. Export auf der Quelle, Import auf dem Ziel, beides aus dem Backend.
Kein SSH-Zugang, kein mysqldump, kein Shell-ZugriffPasst. 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-LimitsPasst. 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 aufsetzenPasst, mit der Einschränkung, dass der Import die Zieldatenbank vollständig ersetzt — siehe Import.
Regelmäßige, automatische Sicherung der SeiteNicht 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 UmzugsNicht 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 übernehmenNicht 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:

  1. Voraussetzungen prüfen — PHP-, Contao- und Rechteanforderungen.
  2. Vor der Installation — Sicherung, Entscheidungen, Testumgebung.
  3. Installation über den Contao Manager — der übliche Weg.
  4. Installation über Composer — die Alternative mit Shell-Zugang.
  5. Installation überprüfen — woran Sie erkennen, dass es geklappt hat.
  6. Lizenz aktivieren — ohne gültige Lizenz bleibt das Modul gesperrt.
  7. Konfiguration — nur nötig, wenn die Standardwerte nicht passen.
  8. Der erste Umzug — der kürzeste vollständige Weg.

Voraussetzungen

AnforderungVersion / WertAnmerkung
PHP^8.2Muss auf Quelle und Ziel erfüllt sein.
Contaocontao/core-bundle ^5.3Contao 4 wird nicht unterstützt.
PHP-Erweiterungenext-json, ext-zlibzlib wird für die gzip-Stücke gebraucht.
Symfony^6.4 oder ^7.0Config, DI, HttpFoundation, HttpKernel.
Doctrine DBAL^3.6 oder ^4.0Die Speicherplatz-Schätzung nutzt information_schema, also MySQL/MariaDB.
Contao-Manager-Plugin^2.0Ausdrücklicher Konflikt mit <2.0 und >=3.0.
LizenzTrial, Free oder ProPro 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:

PfadWofü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.

  1. 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.
  2. Passphrase festlegen und notieren. Sie brauchen dieselbe Zeichenfolge später auf dem Ziel. Warum sie praktisch verpflichtend ist, steht unter Export.
  3. Freien Speicherplatz prüfen. Die Vorprüfung verlangt das Doppelte aus geschätzter Datenbankgröße plus Dateibaum und bricht sonst sofort ab.
  4. 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.
  5. Domain der Startseite auf dem Ziel setzen. Die Lizenzaktivierung bindet an eine konfigurierte Domain; ohne Domain in einer Startseite ist keine Aktivierung möglich.
  6. 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

  1. Contao Manager öffnen und anmelden.
  2. 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.
  3. Über Pakete suchen nach vtinnovations/migrator suchen und beim Treffer Paket hinzufügen wählen.
  4. Änderungen anwenden. Der Contao Manager installiert das Paket und aktualisiert den Autoloader.
  5. Bereich SystemwartungDatenbank-Migrationen und -BackupsDatenbank 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.
  6. 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

  1. 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.“).
  2. 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.
  3. In den Contao-Einstellungen gibt es jetzt die Legende V-T.ONE Licence management mit dem Abschnitt Migrator.
  4. 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

  1. 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.“
  2. Öffnen Sie Contao → Einstellungen und scrollen Sie zur Legende V-T.ONE Licence management, Abschnitt Migrator.
  3. 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.
  4. Tragen Sie den Schlüssel in das Feld Lizenzschlüssel ein (Platzhalter XXXXX-XXXXX-XXXXX-XXXXX).
  5. Klicken Sie auf Lizenz prüfen & aktivieren. Die Schaltfläche sendet das Einstellungsformular ab; es ist kein zusätzliches Speichern nötig.
  6. 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.“
  7. 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.
  8. Öffnen Sie danach das Modul Contao Migrator: Statt der Lizenzkarte erscheinen jetzt die vier Reiter.
SchaltflächeWirkung
Lizenz prüfen & aktivierenPrüft den eingegebenen Schlüssel gegen v-t.one und speichert den signierten Zustand. Meldung bei Erfolg: „Lizenz aktiviert.“
Lizenz aktualisierenErneuert 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 entfernenFragt „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üsselStandardBedeutung
scratch_dir%kernel.project_dir%/var/migratorArbeitsverzeichnis für Aufträge, Backups und Staging. Relative Pfade werden gegen das Projektverzeichnis aufgelöst.
time_budget20.0Sekunden, 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üsselStandardBedeutung
excludesvendor, var/cache, var/log, var/migrator, node_modules, .git, .github, assets/vendorPfade, die nicht ins Dateiarchiv wandern (Präfixvergleich auf den projektrelativen Pfad).
archive_chunk_bytes52428800 (50 MiB)Zielgröße eines files.NNN.tar.gz-Stücks.
push_chunk_bytes4194304 (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_chunk2000Zeilen je INSERT-Stückdatei.
db_max_insert_bytes1048576 (1 MiB)Obergrenze für ein einzelnes INSERT-Statement, damit max_allowed_packet nicht überschritten wird.
retention_backups3Wie viele Backup-Verzeichnisse nach einem Export aufgehoben werden; ältere werden gelöscht.
download_volume_bytes83886080 (80 MiB)Teilgröße, die verwendet wird, wenn beim Download keine eigene Größe angegeben wird.
mailer_policykeepkeep: 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.

  1. Auf dem Ziel: Contao 5.3 installieren, den Migrator installieren und die Lizenz aktivieren.
  2. Auf der Quelle: Modul Contao Migrator öffnen, Reiter Export, eine Passphrase eintragen, Export starten.
  3. Den Auftrag durchlaufen lassen und mögliche Rückfragen beantworten (siehe Pausen und Bestätigungen).
  4. Nach abgeschlossen über Paket herunterladen die .tcmig-Datei sichern — bei großen Paketen über Teildateien.
  5. Auf dem Ziel: Reiter Import, Paketdatei wählen, dieselbe Passphrase eintragen, Hochladen & importieren.
  6. Die Kompatibilitätswarnung bestätigen, falls eine erscheint, und anschließend Alter Host / Neuer Host eintragen und Umschreibung anwenden.
  7. Nach Abschluss die Hinweise im Auftragsprotokoll umsetzen — im Regelfall composer install --no-dev auf dem Ziel; siehe Nachbereitung am Ziel.
  8. 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

  1. Backend → Contao Migrator → Reiter Export.
  2. 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.
  3. Export starten klicken. Der Auftrag wird angelegt, die Seite springt auf den Monitor.
  4. 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.
  5. 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.
  6. Warten, bis der Status abgeschlossen lautet und das Protokoll „Export abgeschlossen — Paket bereit zum Download.“ meldet.
  7. 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:

SchrittWas passiert
VorprüfungErfasst 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-DumpSchema einmal, danach je Tabelle gzip-komprimierte INSERT-Stücke unter db/data/{tabelle}.{NNN}.sql.gz. Wiederaufnehmbar je Tabelle und Position.
Dateien archivierenDer 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.
GeheimnisseVerschlüsselt die drei Schlüssel nach secrets/secrets.enc (Dateirechte 0600), sofern eine Passphrase vorliegt.
Export abschließenSigniert 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

  1. Im Monitor des abgeschlossenen Auftrags erscheint neben Paket herunterladen das Feld Max. MB pro Teil (Vorgabe 10).
  2. Die gewünschte Teilgröße eintragen — sinnvoll ist ein Wert unterhalb von upload_max_filesize und post_max_size des Zielhosts, denn dort müssen die Teile wieder hochgeladen werden.
  3. Teile vorbereiten klicken. Angezeigt wird die Anzahl der Teile, die Gesamtgröße und je Teil ein Link Teil n/m.
  4. Entweder die Teile einzeln anklicken oder Alle nacheinander laden verwenden; die Downloads werden dabei mit kurzem Abstand gestartet, damit der Browser keinen verwirft.
  5. Passt das Paket in eine Datei, meldet die Oberfläche „Paket passt in eine Datei — nutze Download oben.“
  6. Alle Teildateien im selben Ordner behalten. Sie heißen ….tcmig.001, ….tcmig.002 und 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

  1. Auf dem Zielhost anmelden und das Modul Contao Migrator öffnen, Reiter Import.
  2. Unter Paketdatei „(einzelne .tcmig)“ die Paketdatei wählen.
  3. Unter Passphrase „(falls das Paket mit einer Passphrase signiert wurde)“ dieselbe Passphrase eintragen, die beim Export verwendet wurde.
  4. Hochladen & importieren klicken. Der Upload läuft in einem Request — schlägt er an den Serverlimits fehl, nehmen Sie den geteilten Import.
  5. 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.
  6. Erscheint eine Kompatibilitätswarnung, prüfen und mit Trotzdem fortfahren bestätigen.
  7. Bei der Pause zur Host-Umschreibung Alter Host und Neuer Host eintragen und Umschreibung anwenden klicken.
  8. 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:migrate tatsä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

  1. Voraussetzung: Sie haben das Paket auf der Quelle über Teile vorbereiten in Teildateien geladen.
  2. Im Reiter Import unter Alle Teile auf einmal wählen (.001, .002, …) im Dateidialog sämtliche Teildateien markieren.
  3. Die Passphrase in das darunterliegende Feld eintragen.
  4. Hochladen & importieren klicken. Die Teile werden nach Dateinamen sortiert und einzeln nacheinander hochgeladen; die Fortschrittszeile zeigt „Lade Teil 3/7 (…)“.
  5. 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.
  6. Nach dem letzten Teil meldet die Oberfläche „Füge Teile zusammen & starte Import…“ und springt in den Monitor des neuen Import-Auftrags.
  7. 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

  1. Am ZIEL: Reiter Server‑zu‑Server öffnen, Karte Empfangen „(Modus B — ZIEL)“, Kopplungstoken erzeugen klicken.
  2. 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.
  3. An der QUELLE: Reiter Server‑zu‑Server, Karte Senden „(Modus B — QUELLE)“.
  4. Basis-URL des Ziels eintragen, zum Beispiel https://new-host.tld — die Wurzel-URL der Zielinstallation, ohne Pfad.
  5. Den Kopplungstoken einfügen.
  6. 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.
  7. 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.
  8. Nach dem letzten Stück legt das Ziel automatisch einen Import-Auftrag an; das Protokoll der Quelle meldet „Übertragung abgeschlossen — Remote-Import-Auftrag <ID>.“
  9. 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.
  10. 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.

BefundBedeutung
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 portable composer.json als Override ins Paket. Das Paket wird deutlich größer, dafür braucht das Ziel kein composer 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

  1. Der Import pausiert beim Schritt URLs ersetzen, sobald Kandidaten gefunden wurden.
  2. Unter Alter Host die bisherige Domain eintragen, genau so, wie sie in der Datenbank steht (ohne Protokoll, zum Beispiel alt.example.tld).
  3. Unter Neuer Host die künftige Domain eintragen.
  4. Umschreibung anwenden klicken. Der Auftrag läuft weiter und meldet am Ende „URL-Umschreibung fertig (N Wert(e) geändert).“
  5. 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üsselHerkunft nach dem Import
DATABASE_URL, TRUSTED_PROXIES, TRUSTED_HOSTSVom Ziel. Vor dem Auspacken gesichert, danach wieder eingesetzt.
MAILER_DSNVom Ziel, solange mailer_policy auf keep steht (Standard).
APP_SECRET, CONTAO_ENCRYPTION_KEY, DATABASE_ENCRYPTION_KEYVon 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/files nicht, wird ein relativer Symlink angelegt; wo das Dateisystem keine Symlinks erlaubt, wird der Baum kopiert.
  • Cache leeren: var/cache wird geleert, damit der nächste Aufruf den Container gegen die abgeglichene .env.local neu baut.

Danach bleibt eine Aufgabe bei Ihnen, und sie hängt davon ab, ob vendor/ im Paket lag:

PaketProtokollzeileWas 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.“

StatusBedeutung
ausstehendAngelegt, aber noch keine Scheibe gelaufen.
läuftWird gerade vorangetrieben.
pausiertWartet auf eine Eingabe von Ihnen. Weder Browser noch Cron bringen ihn weiter.
abgeschlossenAlle Schritte fertig.
fehlgeschlagenAbgebrochen; der Grund steht in der Statuszeile und im Protokoll.
abgebrochenVom Betreiber abgebrochen.

So brechen Sie einen Auftrag ab oder löschen ihn

  1. Für einen laufenden Auftrag in der Zeile auf Abbrechen klicken (im Monitor gibt es dieselbe Schaltfläche).
  2. Die Rückfrage „Diesen Auftrag abbrechen?“ bestätigen. Der Abbruch greift innerhalb der laufenden Scheibe, nicht erst danach.
  3. Ein abgeschlossener, fehlgeschlagener oder abgebrochener Auftrag zeigt stattdessen Löschen.
  4. 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.
  5. 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

  1. Solange das Backend läuft: Modul Contao Migrator → Reiter WiederherstellungEigenständiges Wiederherstellungs-Panel öffnen →. Der Link enthält den Operator-Token bereits, das Panel öffnet sich in einem neuen Tab.
  2. Notieren Sie sich vorher den darunter angezeigten Wiederherstellungs-Token. Die Oberfläche weist darauf hin, dass er auch in var/migrator/auth.token steht und „nötig wenn das Backend nicht erreichbar ist“.
  3. Wenn das Backend nicht mehr lädt: https://ihre-domain.tld/_tcmig-recovery.php aufrufen, den Token aus var/migrator/auth.token in das Feld Operator-Token eintragen und Wiederherstellungs-Panel öffnen klicken.
  4. 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

  1. Das Panel zeigt oben Status, Schritt und Fortschritt des jüngsten Auftrags sowie das Protokoll.
  2. Aktiven Auftrag antreiben klicken. Die Schaltfläche ruft wiederholt eine Zeitscheibe auf, bis der Auftrag endet.
  3. Verlangt der Auftrag eine Passphrase, erscheint das Feld Export-Passphrase mit Verifizieren & fortfahren — dieselbe Funktion wie im Backend.
  4. Liegen composer.json-Warnungen vor, erscheinen hier ebenfalls Fürs Paket beheben und Trotzdem fortfahren.
  5. Mit Auftrag abbrechen lässt sich ein laufender Auftrag beenden (Rückfrage „Diesen Auftrag abbrechen?“).
  6. 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

  1. Panel öffnen (Token-Anmeldung, siehe oben).
  2. 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)“.
  3. Warten. Beides läuft ohne Shell im Prozess; bei Erfolg meldet das Panel „contao:migrate fertig (Exit 0). Backend neu laden.“
  4. 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.
  5. 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ähigkeitUmfasstTrialFreePro
Export, Import & WiederherstellungPaket erstellen, herunterladen (auch geteilt), hochladen und einspielen, Aufträge verwalten, Wiederherstellungs-Panel
Server-zu-Server-ÜbertragungKopplungstoken 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.“

StatuszeileBedeutung
Nicht lizenziertKein gültiger Zustand gespeichert. Das Modul zeigt nur den Verweis auf die Einstellungen.
Testlizenz aktivTrial — enthält auch die Server-zu-Server-Übertragung, damit die kostenpflichtige Fähigkeit geprüft werden kann.
Free-Lizenz aktivExport, Import und Wiederherstellung.
Pro-Lizenz aktivVoller Umfang.
Pro-Lizenz abgelaufen — Free-Funktionsumfang aktivAbgelaufene Pro-Lizenz, deren Paket den Free-Rückfall erlaubt: Export, Import und Wiederherstellung laufen weiter, die direkte Übertragung nicht.
Lizenz abgelaufenAbgelaufen ohne Rückfall — das Modul ist gesperrt.
Lizenz kann auf dieser Installation nicht geprüft werdenDer 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.

AuftragstypSchrittfolge
Export (Modus A)preflightdump_databasearchive_filessecretsfinalize_export
Push (Modus B, Quelle)wie Export, danach build_packagepush_package
Import (A und B)unpack_packageverify_packagecompat_gatecapture_dest_configsafety_snapshotextract_filesrestore_databaseurl_replaceconfig_reconcilepost_migrationfinalize_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

NameMethode und PfadZugang
tcmig_statusGET /contao/migrator/status/{id}Backend-Firewall. Nur lesend; treibt den Auftrag bewusst nicht voran.
tcmig_tickGET /contao/migrator/tick/{id}Backend-Firewall. Eine Zeitscheibe je Aufruf.
tcmig_downloadGET /contao/migrator/download/{id}Backend-Firewall. ?meta=1 liefert Größe und Teileanzahl, ?part=N&vol=MB einen Byte-Ausschnitt.
tcmig_upload_partPOST /contao/migrator/upload-part/{isess}Backend-Firewall, CSRF-geprüft.
tcmig_assemblePOST /contao/migrator/assemble/{isess}Backend-Firewall, CSRF-geprüft.
tcmig_cancelPOST /contao/migrator/cancel/{id}Backend-Firewall, CSRF-geprüft.
tcmig_deletePOST /contao/migrator/delete/{id}Backend-Firewall, CSRF-geprüft.
tcmig_ingest_chunkPOST /migrator/ingest/{session}Öffentlich, authentifiziert per HMAC über den Einmal-Kopplungsschlüssel. Verlangt die Pro-Fähigkeit auf dem Ziel.
tcmig_ingest_finalizePOST /migrator/ingest/{session}/finalizeWie 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:

ParameterWert
vtinnovations_migrator.scratch_dirStandard %kernel.project_dir%/var/migrator
vtinnovations_migrator.time_budgetStandard 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

PfadInhalt
var/migrator/jobs/<id>.jsonDer Auftrag: Schritte, Cursor, Metadaten, Protokoll.
var/migrator/jobs/<id>.secretTransiente Passphrase (0600). Wird beim Abschluss des Exports beziehungsweise des Imports gelöscht und steht nie in der Auftragsdatei.
var/migrator/jobs/<id>.cancelAbbruchmarkierung, 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.jsonLaufzeitwerte. Wird nur gelesen.
var/migrator/auth.tokenOperator-Token (0600) für das Wiederherstellungs-Panel; Signaturschlüssel für Pakete ohne Passphrase.
var/migrator/pairings.jsonOffene 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.phpDas 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:

EintragInhalt
manifest.jsonUmgebung, Startseiten-Hosts, URL-Kandidaten, Speicherschätzung, Tabellen- und Datei-Stücke mit SHA-256, Signaturverfahren, Signatur.
db/schema.sqlDas Schema aller Tabellen.
db/data/{tabelle}.{NNN}.sql.gzDie Daten als gzip-komprimierte INSERT-Stücke.
files/files.{NNN}.tar.gzDer Projektbaum ohne die ausgeschlossenen Pfade.
secrets/secrets.encDie verschlüsselten Geheimnisse — nur vorhanden, wenn eine Passphrase gesetzt war.
overrides/composer.jsonDie portable composer.json — nur beim Weg „Fürs Migrations-Paket beheben“.
checksums.jsonPrü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

ZielWannInhalt
Lizenzdienst von V-T.ONEBeim Aktivieren und Aktualisieren der LizenzDer Lizenzschlüssel und die gewählte konfigurierte Domain. Die Antwort wird signiert geprüft, bevor sie gespeichert wird.
V-T.ONEBeim Öffnen des Backend-ModulsEin 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 ZielsBeim Server-zu-Server-PushDie 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:migrate und assets:install im 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

SymptomUrsache 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 fehlDas 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 abpost_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 mehrEine 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 voranContaos 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 Stylesheetspublic/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 nichtIn 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 unlesbarDer 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 DatenbankfehlerDas 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 deaktiviertDer 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-NavigationDas 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 .env und .env.local des 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

  1. Alle Aufträge abschließen oder abbrechen. Ein laufender Auftrag schreibt sonst in ein Verzeichnis, das gleich verschwindet.
  2. Im Abschnitt Migrator der Contao-Einstellungen auf Lizenz entfernen klicken und die Rückfrage bestätigen, damit der Lizenzplatz wieder frei wird.
  3. Das Paket entfernen — im Contao Manager unter Pakete, oder per Composer:
    composer remove vtinnovations/migrator
    vendor/bin/contao-console cache:clear
  4. 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.
  5. Die Datei public/_tcmig-recovery.php löschen. Sie bleibt sonst im Web-Root liegen; ohne Bundle ist sie funktionslos, gehört aber trotzdem entfernt.
  6. Datenbankseitig ist nichts aufzuräumen — das Paket hat keine eigenen Tabellen angelegt.