Von Heroku migrieren

Eine Heroku-App mit Datenbank, Config Vars und Domain umziehen.

Diese Anleitung zieht eine Heroku-App zu Nodion um: Code, Config Vars, Heroku Postgres, Heroku Key-Value Store, Scheduler-Jobs und die eigene Domain. Plane eine kurze Schreibpause ein, während die Datenbank kopiert wird. Einen Import für app.json oder heroku.yml gibt es nicht; jeder Schritt unten sind ein paar Klicks oder Befehle.

Was wozu wird

HerokuNodion
AppApplication
Process Types und Dynos (web, worker)Prozesse einer App, jeder mit eigenen Replicas und eigenem Paket
Dyno-GrößePaket (Discovery, General Purpose)
Config VarsUmgebungsvariablen (Tab Environment)
ProcfileProcfile (bei Buildpack-Builds)
Release PhaseProcfile-Eintrag release: oder der Release Command der App
Heroku PostgresManaged Postgres, angehängt als DATABASE_URL
Heroku Key-Value StoreValkey, angehängt als REDIS_URL
Heroku SchedulerCron Jobs der App
Review AppsPreview-Environments
Automated Certificate ManagementAutomatische Zertifikate

1. Projekt und Datenbank anlegen

Leg ein Projekt an und darin eine PostgreSQL-Datenbank in der Region, in der die App laufen soll (EU Central für Frankfurt). App und Datenbank müssen in derselben Region liegen, sonst lehnt Nodion das Anhängen ab. Wähl eine Postgres-Version, die mindestens so neu ist wie deine Heroku-Datenbank. Mehr unter Datenbanken.

2. Datenbank kopieren

Stopp zuerst alle Schreibzugriffe. Im Maintenance Mode von Heroku laufen Worker-Dynos und Scheduler-Jobs weiter. Skalier deshalb jeden Process Type, der schreibt, auf null (nicht nur worker) und entferne die Jobs im Heroku Scheduler für die Dauer der Kopie. Auf Fir-Apps gibt es laut Heroku keinen Maintenance Mode; dort skalierst du auch web auf null oder stoppst die Schreibzugriffe in der App selbst:

bashheroku maintenance:on --app example-app
heroku ps:scale worker=0 --app example-app   # every process type that writes

Auf Fir:

bashheroku ps:scale web=0 worker=0 --app example-app   # Fir: no maintenance mode

Dann ein Backup erstellen und herunterladen. Heroku schreibt es als latest.dump im Custom-Format von pg_dump (Heroku-Doku). Heroku empfiehlt PGBackups für Datenbanken bis 20 GB; bei größeren nimm pg_dump direkt mit der URL aus heroku pg:credentials:url (Classic-Datenbanken) oder heroku data:pg:credentials:url (Advanced-Datenbanken, Heroku-Doku).

bashheroku pg:backups:capture --app example-app
heroku pg:backups:download --app example-app

Advanced-Datenbanken unterstützen PGBackups nicht; für sie, und für Datenbanken über 20 GB, dumpst du direkt im selben Custom-Format, mit der URL aus dem passenden Credentials-Befehl. Private- und Shield-Datenbanken lassen laut Heroku keine externen Verbindungen zu (Shield auch kein PGBackups); folge für sie dem Weg, den Heroku für Private Spaces beschreibt.

bashpg_dump -Fc --no-acl --no-owner -f latest.dump \
  "postgres://USER:PASSWORD@HOST:5432/DATABASE?sslmode=require"

Öffne in Nodion die Datenbank, Tab Overview, und klick bei Public access auf Enable public access. Warte, bis der Endpoint nicht mehr Provisioning zeigt, und kopier dann die Connection URL, die das Dashboard anzeigt (immer TLS, sslmode=require). Trag unter den erlaubten Quellen deine eigene IP ein, damit nur du dich verbinden kannst. Dann einspielen:

bashpg_restore --verbose --no-owner --no-acl \
  --dbname "postgresql://nodion:PASSWORD@HOST:PORT/DATABASE?sslmode=require" \
  latest.dump

Nimm ein pg_restore, das mindestens so neu ist wie der neuere der beiden Server. Meldet der Restore Fehler zum Schema heroku_ext, leg es vorher an: CREATE SCHEMA heroku_ext; (der Tipp stammt von Heroku). Prüf Zeilenzahlen im Tab Browse der Datenbank und schalte den öffentlichen Zugang danach wieder ab; die Datenbank läuft intern weiter.

Ein leerer Valkey reicht nur, wenn deine App den Key-Value Store als Cache nutzt oder als Queue, die du vorher leerlaufen lässt. Liegen dort Daten, die du brauchst (etwa Sessions oder dauerhafte Keys), zieh sie vor dem Abschalten um oder behalte die Quelle, bis sie nicht mehr gebraucht werden.

3. Application anlegen

Leg eine Application aus deinem Git-Repository an, mit der Strategie Buildpacks. Die Buildpacks lesen dein Procfile: web ist der Standardprozess, die anderen Zeilen werden Process Types (Buildpacks). Bei Node.js läuft ein heroku-postbuild-Script nach dem Build. Wie auf Heroku bekommt der web-Prozess die Variable PORT.

Fehlt im Procfile eine Zeile web:, wird die erste Zeile zum Standard und läuft im web-Prozess von Nodion. Diesen Prozess prüft Nodion vor dem Livegang per HTTP; ein Worker ohne HTTP-Server besteht diese Prüfung nicht. Behalte deshalb eine Zeile web: für den HTTP-Server deiner App.

Procfile-Zeilen legen keine Prozesse an. Für eine Zeile worker: öffnest du Processes, New process, nennst ihn worker und lässt den Befehl leer; dann läuft der gleichnamige Process Type.

Eine Zeile release: läuft bei jedem Deploy einmal, bevor web startet. Schlägt sie fehl, schlägt der Deploy fehl und das vorherige Release bedient weiter. Hast du auf Heroku mit heroku.yml gebaut, nimm die Strategie Dockerfile: Dort gibt es kein Procfile, setz den Release Command der App (Settings, Karte Preview environments, wo das Feld erscheint, sobald Previews aktiviert sind, oder release_command über die API). Bei Dockerfile-Apps setzt Nodion kein PORT; die App lauscht auf dem Port des web-Prozesses (sonst dem EXPOSE des Images, sonst 8080).

4. Config Vars übernehmen

Exportier die Config Vars im Shell-Format (Heroku CLI):

bashheroku config -s --app example-app > heroku.env

Füg die Zeilen unter Environment, Add many ein und importier sie. Prüf das Ergebnis: Werte mit Anführungszeichen oder Backslashes musst du eventuell von Hand korrigieren, mehrzeilige Werte (etwa PEM-Keys) setzt du per CLI oder API. Importierte Variablen sind nicht geheim; Secrets setzt du mit nodion env set KEY=wert --secret.

Lösch danach DATABASE_URL und REDIS_URL aus den importierten Variablen: Eine selbst gesetzte Variable überschreibt den Wert, den eine angehängte Datenbank einspielt. Häng dann über Attach database die Postgres-Datenbank (url als DATABASE_URL) und Valkey (url als REDIS_URL) an.

Intern läuft die Verbindung über das private Netz ohne TLS (sslmode=disable). Erzwingt dein Code SSL für die Datenbank, wie es auf Heroku nötig ist, schalte das für diese URL ab; dasselbe gilt für rediss:// zu Valkey.

5. Scheduler-Jobs als Cron Jobs

Leg jeden Job aus dem Heroku Scheduler im Tab Cron der App an: Zeitplan als Cron-Ausdruck mit fünf Feldern in UTC, derselbe Befehl, ein Timeout bis 30 Minuten. Pro App gehen bis zu 8 Cron Jobs; läuft ein Job noch, fällt der nächste Termin aus.

6. Deployen und prüfen

Deploye, verfolg den Tab Logs und öffne die App unter ihrem Nodion-Hostnamen. Antwortet / nicht schnell mit 2xx oder 3xx, setz unter Settings einen eigenen Health-Check-Pfad.

7. Domain umziehen

Trag die Domain im Tab Domains ein. Nodion zeigt zwei Records: einen TXT-Record _nodion-challenge.deine-domain und einen CNAME (am Apex ein ALIAS) auf den Standard-Hostnamen der App. Den TXT-Record kannst du vorab setzen. Das Zertifikat wird ausgestellt, sobald der CNAME auf Nodion zeigt; rechne nach dem Umschalten mit ein paar Minuten ohne gültiges Zertifikat und senk die TTL vorher.

8. Heroku abschalten

Wenn Traffic und Daten auf Nodion laufen, lösch die Heroku-App. Das lässt sich laut Heroku nicht rückgängig machen, behalte also latest.dump.

bashheroku apps:destroy --app example-app

Was anders ist

  • Es gibt keinen Maintenance Mode und keine Pipelines mit Promotion zwischen Apps.
  • Statt One-off-Dynos öffnet der Tab Shell ein Terminal in einem laufenden Prozess.
  • Die CLI holt Logs, kann ihnen aber nicht folgen; live mitlesen kannst du im Tab Logs.
  • Preview-Environments brauchen kein app.json; jedes bekommt eine leere Datenbank.
  • Ein Rollback deployt ein früheres Image mit den aktuellen Umgebungsvariablen.

Weiter

Nodion und Heroku im Vergleich, Preise, Applications und Datenbanken.

Gib deinem Agenten eine Cloud.

Bis zu 15 € Guthaben beim Registrieren.

Weiter mit GitHub

oder per E-Mail

Bleib auf dem Laufenden.

Produktnews, kein Spam. Jederzeit abbestellen.