Zum Inhalt
flowplanDokumentationCommunityZur Startseite

Selbst hosten

Instanz umziehen

So bringst du eine ganze Flowplan-Instanz auf einen anderen Server – etwa vom Heimserver auf einen gemieteten Server –, mit allen Konten, Arbeitsbereichen, Dateien und Schlüsseln und meist nur wenigen Minuten Ausfallzeit.

Eine Flowplan-Instanz besteht aus genau vier Dingen:

TeilWasZieht mit um
Containerdas Image ghcr.io/yannicschuller/flowplan (für linux/amd64 und linux/arm64)neu installieren, dieselbe oder eine neuere Version
Datenordner /app/dataflowplan.sqlite (+ -wal, -shm), uploads/, web-push-keys.json, secrets.key; ocr/ und tmp/ entstehen neuja – das ist der eigentliche Umzug
UmgebungsvariablenAPP_URL, Schlüssel, OIDC_*, S3_*, SMTP_* …von Hand übernehmen, vor allem die Schlüssel
Domain und Reverse ProxyDNS-Eintrag, HTTPS-ZertifikatDNS umstellen, Proxy neu einrichten

Das gilt für jede Art des Betriebs: docker run, Docker Compose, Kubernetes mit dem Helm-Chart, ohne Docker oder in einem Verwaltungs-Panel. Nutzt du ein Panel, legst du dort denselben Container mit demselben Volume und denselben Variablen neu an.

Vorbereiten

  1. Umgebungsvariablen aufschreiben. Alle, die die alte Instanz bekommt – je nach Betrieb aus der .env, mit docker inspect <container> (Abschnitt Env), docker compose config oder helm get values flowplan. Die vollständige Liste steht unter Konfiguration.
  2. Die Schlüssel sichern, getrennt von den Daten (Passwortmanager):
    • FLOWPLAN_ENCRYPTION_KEY (oder die Datei aus FLOWPLAN_ENCRYPTION_KEY_FILE) und FLOWPLAN_ENCRYPTION_KEY_PREVIOUS: Ohne sie sind verschlüsselte Sicherungen, die verschlüsselten Dateien im Bucket und die damit verschlüsselten gespeicherten Geheimnisse unlesbar.
    • FLOWPLAN_SECRETS_KEY (oder …_FILE), falls gesetzt. Ist keiner der beiden gesetzt, liegt der Schlüssel für gespeicherte Geheimnisse als secrets.key im Datenordner – das eingebaute Umzugswerkzeug nimmt ihn mit, bei den anderen Wegen kopierst du ihn selbst.
    • Was davon abhängt: KI-Schlüssel, Kalenderverbindungen (Google, Microsoft 365), Chat-App-Tokens, Git-Export-Tokens und die Zwei-Faktor-Geheimnisse der Konten. Fehlt der Schlüssel, kommen Konten mit Zwei-Faktor-Anmeldung nur noch mit Wiederherstellungscodes hinein.
  3. Die Domain behalten. Gleiche APP_URL heißt: Passkeys, die OIDC-Weiterleitung, CalDAV- und CardDAV-Konten, die Apps, eingehende Webhooks (Git, Tickets, E-Mail-Eingang) und Freigabelinks funktionieren nach dem DNS-Wechsel einfach weiter. Mit einer neuen Domain muss all das neu eingerichtet werden (siehe Andere Domain).
  4. Die TTL des DNS-Eintrags senken, mindestens so lange vorher, wie die bisherige TTL beträgt (oft 1 bis 24 Stunden), z. B. auf 300 Sekunden. Dann greift die Umstellung später in Minuten.
  5. Den neuen Server einrichten (Beispiel: Hetzner Cloud) mit derselben oder einer neueren Flowplan-Version – eine ältere kann eine neuere Datenbank nicht öffnen – und mit denselben Umgebungsvariablen. Ein eigenes S3-Bucket für die neue Instanz ist am einfachsten; mit demselben Bucket siehe Weg C.
  6. Eine Sicherung anlegen: Administration → Speicher & Sicherung → Gesamte Instanz → Herunterladen. Sie schadet nie.
  7. Die Nutzer vorwarnen: Administration → Wartung & Hinweise zeigt allen ein Wartungsfenster an.

Drei Wege

WegWannAusfallzeit
A: Umzugswerkzeug (empfohlen)immer, wenn der neue Server den alten erreichtMinuten (nur der letzte Abgleich)
B: Sicherung herunterladen und hochladenkleine Instanzen, kein Netzweg zwischen den Servernvon der Sicherung bis zum Start der neuen Instanz
C: S3 und Litestreamdie alte Instanz läuft schon mit S3 und LitestreamStoppen der alten bis Start der neuen Instanz

Weg A: Das Umzugswerkzeug

Unter Administration → Speicher & Sicherung (nur für Admins) holt die neue Instanz alles direkt von der alten: von Server zu Server, fortsetzbar und mit Prüfsummen.

Auf der alten Instanz – „Umzug vorbereiten“

  1. Instanz umziehen → Umzug vorbereiten. Zur Sicherheit fragt Flowplan nach deinem Passwort; bei Anmeldung über SSO muss die Anmeldung höchstens 15 Minuten alt sein (sonst einmal ab- und wieder anmelden).
  2. Flowplan zeigt die Übertragungsadresse und das Umzugstoken (fpmove_…) – nur dieses eine Mal. Das Token gilt 24 Stunden und nur für den Umzug: Es darf die Instanz lesen, sie für den letzten Abgleich schreibschützen und den Umzug abschließen, sonst nichts. Gespeichert wird nur ein Hash; Widerrufen macht es sofort ungültig, ein neues Token ersetzt das alte. Das Erstellen, Widerrufen und jeder Schritt des Umzugs stehen im Aktivitätsprotokoll und als Sicherheitsereignis unter Administration → Sicherheit. Zehn falsche Token-Versuche von einer Adresse sperren sie für 15 Minuten.

Auf der neuen Instanz – „Von anderer Instanz übernehmen“

Die neue Instanz ist frisch: nur das erste Admin-Konto, das du beim ersten Start anlegst. Hat sie schon Inhalte, verlangt Flowplan eine ausdrückliche Bestätigung, denn alles wird ersetzt.

  1. Instanz umziehen → Von anderer Instanz übernehmen: die Adresse der alten Instanz (ihre APP_URL) und das Umzugstoken eintragen, Übernahme starten.

    • Steht der alte Server nur im eigenen Netz (LAN, VPN wie WireGuard oder Tailscale, z. B. http://192.168.1.10:3000), auf der neuen Instanz vorübergehend FLOWPLAN_MOVE_ALLOW_PRIVATE=true setzen. Ohne diese Variable sind wie bei allen Abrufen des Servers nur öffentliche https://-Adressen erlaubt.
  2. Erste Kopie: ein konsistenter Datenbankstand, alle Dateien aus uploads/ einzeln mit SHA-256-Prüfsumme, web-push-keys.json und secrets.key. Die Seite zeigt Bytes, Dateien und die geschätzte Restzeit. Die alte Instanz läuft währenddessen normal weiter. Bricht die Verbindung ab oder startet ein Server neu, geht es mit Fortsetzen an derselben Stelle weiter – bereits geprüfte Dateien werden nicht noch einmal geholt, eine halbe Datei wird ab ihrem letzten Byte fortgesetzt.

  3. Vorabprüfung → Prüfen. Flowplan vergleicht die Einstellungen beider Instanzen – nur Namen und Prüfwerte (HMAC mit dem Umzugstoken), nie die Werte selbst – und prüft, ob die neue Instanz S3, SMTP und den OIDC-Anbieter erreicht. Das Ergebnis ist eine Liste mit OK, Warnung und Fehler:

    PrüfungBedeutung
    VersionFehler, wenn die neue Instanz älter ist als die alte: zuerst aktualisieren.
    FLOWPLAN_ENCRYPTION_KEYFehler, wenn er fehlt oder ein anderer ist: Verschlüsselte Sicherungen, die verschlüsselten Dateien im Bucket, gespeicherte Tokens und Kalenderverbindungen wären unlesbar. Den alten Schlüssel setzen (ein neuer höchstens zusätzlich, der alte dann in …_PREVIOUS).
    Gespeicherte GeheimnisseFehler, wenn der Schlüssel dafür fehlt (FLOWPLAN_SECRETS_KEY bzw. FLOWPLAN_ENCRYPTION_KEY). Ein erzeugtes secrets.key kommt automatisch mit.
    APP_URLWarnung bei einer anderen Adresse, mit allem, was dann neu einzurichten ist.
    OIDC, S3, SMTP, Push, KI, weitereVariablen, die hier fehlen, einen anderen Wert haben oder nur hier gesetzt sind. Fehlende OIDC_ISSUER/OIDC_CLIENT_ID sind ein Fehler – sonst kommt niemand per SSO hinein.
    Gleicher BucketWarnung: Beide Instanzen schreiben sonst in denselben Ordner (siehe Weg C).
    S3, SMTP, OIDC erreichbarFehler mit der Meldung des Dienstes. Ports 25 und 465 sperren viele Anbieter ausgehend – dann Port 587.

    Ändere die Variablen der neuen Instanz und starte sie neu, bis keine Fehler mehr bleiben; der Umzug geht nach dem Neustart weiter.

  4. Quelle schreibschützen und letzten Stand holen: Ab hier beginnt die Ausfallzeit. Die alte Instanz nimmt keine Änderungen mehr an – alle sehen „Umzug läuft: Diese Instanz ist schreibgeschützt“, Lesen und Anmelden gehen weiter, Änderungen (auch über API, CalDAV, Webhooks, eingehende E-Mails) werden mit einer klaren Meldung abgelehnt. Die neue Instanz holt einen frischen Datenbankstand und nur die Dateien, die seit der ersten Kopie neu sind oder sich geändert haben; entfernte fallen weg. Das dauert meist Minuten.

  5. Beim Neustart übernehmen → Übernehmen: Flowplan prüft die Datenbank und legt alles für den nächsten Start bereit – genau wie Aus Sicherung wiederherstellen. Die alte Instanz bekommt Bescheid: Sie zeigt jetzt „Diese Instanz ist umgezogen nach …“, bleibt schreibgeschützt, und ihr Umzugstoken ist verbraucht.

  6. Die neue Instanz neu starten (den Container, den Pod bzw. den Dienst). Beim Start ersetzt Flowplan Datenbank, Dateien und Schlüssel; der vorherige Stand der neuen Instanz bleibt als pre-move-<Zeit> im Datenordner. Im Protokoll steht Instanz wiederhergestellt; vorheriger Stand in …/pre-move-….

  7. DNS umstellen (unten) und danach prüfen.

Anmelden kannst du dich auf der neuen Instanz jetzt mit den Konten der alten; das erste Admin-Konto der neuen ist ersetzt. Bestehende Anmeldungen (Browser, Apps) gelten weiter, solange die Domain gleich bleibt.

Auf der alten Instanz lässt sich unter Instanz umziehen noch Weboberfläche weiterleiten einschalten: Wer sie im Browser öffnet, landet direkt auf der neuen Adresse. Schreibschutz aufheben macht sie wieder beschreibbar – nur, wenn der Umzug abgebrochen wird.

Ohne Oberfläche (Kommandozeile)

Dasselbe ohne Weboberfläche auf der neuen Instanz – etwa bevor dort überhaupt ein Konto existiert, oder über SSH, solange das DNS noch auf den alten Server zeigt. Das Werkzeug liegt im Image unter /app/move.mjs und im Quellcode unter scripts/move.mjs (npm run move). Es holt die erste Kopie, schaltet die alte Instanz schreibgeschützt, holt den letzten Stand, legt alles für den nächsten Start bereit und meldet der alten Instanz die neue Adresse (--target-url, sonst APP_URL). Abgebrochen? Denselben Befehl noch einmal ausführen – er macht an derselben Stelle weiter.

# Docker Compose (im Ordner der neuen Instanz; gleiche .env, gleiches Volume)
docker compose run --rm flowplan node /app/move.mjs \
  --from https://flowplan.example.org --token fpmove_…
docker compose up -d          # startet und übernimmt die Kopie

# docker run
docker run --rm -v flowplan-data:/app/data -e APP_URL=https://flowplan.example.org \
  ghcr.io/yannicschuller/flowplan node /app/move.mjs --from https://flowplan.example.org --token fpmove_…

# Kubernetes (Helm-Chart)
kubectl -n flowplan exec deploy/flowplan -- node /app/move.mjs --from https://flowplan.example.org --token fpmove_…
kubectl -n flowplan rollout restart deploy/flowplan

# ohne Docker
npm run move -- --from https://flowplan.example.org --token fpmove_… --data /var/lib/flowplan
OptionBedeutung
--from <Adresse>Adresse der alten Instanz. Auf der Kommandozeile sind auch interne Adressen und http:// erlaubt – du entscheidest, wohin sie sich verbindet.
--token <Token>Das Umzugstoken (oder FLOWPLAN_MOVE_TOKEN in der Umgebung, damit es nicht in der Shell-History landet).
--data <Ordner>Datenordner, Standard FLOWPLAN_DATA_DIR bzw. ./data.
--target-url <Adresse>Adresse der neuen Instanz für den Hinweis auf der alten (Standard APP_URL).
--copy-onlyNur die erste Kopie; die alte Instanz bleibt beschreibbar. Später ohne die Option noch einmal für den letzten Abgleich.
--yesEinen Datenordner ersetzen, der schon Inhalte hat (der bisherige Stand bleibt als pre-move-…).

Die Vorabprüfung gibt es nur in der Oberfläche; auf der Kommandozeile vergleichst du die Variablen selbst (Liste oben).

Weg B: Sicherung herunterladen und hochladen

  1. Auf der alten Instanz Wartung ankündigen – Änderungen nach dem Herunterladen gehen verloren.
  2. Administration → Speicher & Sicherung → Gesamte Instanz → Herunterladen. Mit FLOWPLAN_ENCRYPTION_KEY ist die Datei verschlüsselt (.zip.enc) – die neue Instanz braucht dann denselben Schlüssel.
  3. Die Instanzsicherung enthält Datenbank und Dateien, aber nicht secrets.key und web-push-keys.json. Beide von Hand kopieren (oder die Schlüssel als Variablen setzen):
    # alt
    docker compose cp flowplan:/app/data/secrets.key .
    docker compose cp flowplan:/app/data/web-push-keys.json .
    # neu
    docker compose cp secrets.key flowplan:/app/data/
    docker compose cp web-push-keys.json flowplan:/app/data/
    docker compose exec -u root flowplan chown node:node /app/data/secrets.key /app/data/web-push-keys.json
  4. Auf der neuen Instanz Aus Sicherung wiederherstellen → Sicherung auswählen. Der Proxy davor muss so große Uploads durchlassen (Caddy von sich aus, nginx mit client_max_body_size, Cloudflare höchstens 100 MB); sonst die Datei per scp auf den Server bringen und dort hochladen. Höchstens 50 GB.
  5. Neu starten; der vorherige Stand bleibt als pre-restore-…. Dann DNS umstellen.

Weg C: S3 und Litestream

Läuft die alte Instanz mit S3 (Dateien im Bucket) und Litestream (laufende Kopie der Datenbank unter <Präfix>/db/), kann die neue Instanz direkt aus dem Bucket starten:

  1. Die alte Instanz stoppen – Litestream beider Instanzen dürfen nie gleichzeitig in denselben Ordner schreiben.
  2. Die neue Instanz mit denselben S3_*-Variablen, demselben FLOWPLAN_ENCRYPTION_KEY und einem leeren Datenordner starten. Litestream stellt die Datenbank wieder her, die Dateien holt Flowplan beim ersten Abruf sofort und alle übrigen im Hintergrund.
  3. secrets.key und web-push-keys.json wie in Weg B kopieren, falls die Schlüssel nicht als Variablen gesetzt sind.
  4. DNS umstellen.

Mit FLOWPLAN_LITESTREAM=off gibt es keine laufende Kopie: dann die neueste geplante Sicherung aus <Präfix>/backups/ verwenden (siehe Wiederherstellen). Die Vorabprüfung von Weg A erkennt eine Litestream-Kopie im Bucket und weist auf diesen Weg hin.

DNS umstellen

  1. Nach dem letzten Abgleich (Weg A) bzw. dem Start der neuen Instanz den A-Eintrag (IPv4) und den AAAA-Eintrag (IPv6) der Domain auf den neuen Server ändern. Am alten Standort eine Portweiterleitung oder einen Tunnel entfernen.
  2. Der Proxy des neuen Servers holt das Zertifikat, sobald die Domain auf ihn zeigt (bei Let's Encrypt über Port 80) – eine Minute Geduld.
  3. Mit dig +short flowplan.example.org (oder nslookup) prüfen, was die Welt sieht. Wer die alte Adresse noch im Cache hat, landet bis zum Ablauf der TTL auf der alten Instanz – dort steht dann der Hinweis auf die neue.
  4. Danach die TTL wieder anheben.

Danach prüfen

  • Anmelden: mit Passwort, Passkey und SSO. Bestehende Sitzungen gelten weiter.
  • Administration → Überwachung: alles grün? Administration → Verschlüsselung zeigt dieselbe Schlüssel-ID wie vorher.
  • Administration → Speicher & Sicherung: S3 verbunden, Warteschlange läuft leer (mit S3 lädt Flowplan nach einer Übernahme alle Dateien einmal hoch), Jetzt sichern gelingt.
  • Administration → E-Mail → Test-E-Mail senden und Administration → Push-Benachrichtigungen → Testbenachrichtigung senden.
  • Ein paar Seiten, Bilder und Anhänge öffnen; eine Datei hochladen.
  • KI, Kalenderverbindungen, Chat-Apps: funktionieren sie ohne neue Anmeldung, sind die gespeicherten Geheimnisse lesbar.
  • CalDAV/CardDAV in einer App aktualisieren, die Desktop- und Mobil-Apps öffnen, eingehende Webhooks (Git, Tickets) einmal auslösen.

Aufräumen

  • Auf der neuen Instanz FLOWPLAN_MOVE_ALLOW_PRIVATE wieder entfernen.
  • pre-move-… (bzw. pre-restore-…) im Datenordner nach ein paar Tagen löschen, z. B. docker compose exec flowplan sh -c 'rm -rf /app/data/pre-move-*'.
  • Die alte Instanz noch einige Tage mit dem Hinweis laufen lassen, dann stoppen, das Volume sicher löschen und ihre S3-Zugangsdaten (falls eigene) widerrufen. Das Umzugstoken ist schon verbraucht.
  • Eine geplante Sicherung auf der neuen Instanz einschalten bzw. prüfen (Sicherungen).

Zurück, falls etwas schiefgeht

Bis zum DNS-Wechsel ist nichts verloren: Auf der alten Instanz Administration → Speicher & Sicherung → Instanz umziehen → Schreibschutz aufheben, und alles läuft weiter wie vorher. Nach dem Wechsel: DNS zurückstellen und den Schreibschutz aufheben – was auf der neuen Instanz inzwischen geändert wurde, kommt nur mit einem Umzug in die Gegenrichtung zurück. Die neue Instanz selbst kehrt zu ihrem vorherigen Stand zurück, indem du bei gestopptem Container flowplan.sqlite* und uploads/ durch den Inhalt von pre-move-… ersetzt.

Andere Domain

Bekommt die Instanz eine neue Adresse, setze APP_URL auf die neue und richte danach neu ein:

  • Passkeys sind an die Domain gebunden: Alle melden sich mit Passwort oder SSO an und legen sie neu an.
  • OIDC: die Weiterleitungsadresse beim Anbieter auf <neue APP_URL>/api/auth/callback ändern.
  • CalDAV und CardDAV: Konten in den Kalender- und Kontakte-Apps neu einrichten.
  • Eingehende Webhooks (Git, Ticket-Sync, E-Mail-Eingang) und Freigabelinks zeigen auf die alte Adresse.
  • Desktop- und Mobil-Apps speichern die Adresse des Servers. Sie verbinden sich weiter mit der alten Instanz; dort sehen alle den Hinweis „Diese Instanz ist umgezogen nach …“, und Änderungen werden mit einer Meldung abgelehnt, die die neue Adresse nennt. In der App abmelden und die neue Adresse eintragen (Desktop: Profile → Profil hinzufügen …). Weboberfläche weiterleiten dabei ausgeschaltet lassen: Die Apps nehmen keine Adresse an, die auf eine andere Seite weiterleitet.

Fehlersuche

Meldung oder ZustandUrsache und Lösung
„Interne Adressen sind nur mit FLOWPLAN_MOVE_ALLOW_PRIVATE=true erlaubt“Die alte Instanz hat eine private Adresse (LAN, VPN, localhost) oder nur http://. Auf der neuen Instanz FLOWPLAN_MOVE_ALLOW_PRIVATE=true setzen, neu starten, nach dem Umzug wieder entfernen.
„Ungültiges oder abgelaufenes Umzugstoken“Falsch kopiert, älter als 24 Stunden, widerrufen, durch ein neues ersetzt oder durch einen abgeschlossenen Umzug verbraucht. Auf der alten Instanz ein neues erzeugen.
„Zu viele ungültige Umzugsanfragen“Zehn falsche Tokens von einer Adresse: 15 Minuten warten.
Übertragung bricht abFortsetzen (bzw. den Befehl noch einmal ausführen). Fertige Dateien bleiben, halbe werden fortgesetzt.
„Prüfsumme stimmt nicht“Die Datei kam beschädigt an und wird automatisch neu geladen; bleibt es dabei, die Verbindung (Proxy, VPN) prüfen.
„Dieser Datenbankstand ist nicht mehr vorhanden“Die alte Instanz hat inzwischen einen neuen Stand erzeugt (neues Token, Neustart). Fortsetzen holt ihn.
Zeitüberschreitung beim Start (502/504)Beim ersten Mal berechnet die alte Instanz die Prüfsummen aller Dateien. Ein Proxy mit kurzem Zeitlimit davor (nginx: proxy_read_timeout 60 s, Cloudflare 100 s) bricht ab. Zeitlimit erhöhen oder die Adresse ohne Proxy verwenden (mit FLOWPLAN_MOVE_ALLOW_PRIVATE).
Vorabprüfung: Fehler bei FLOWPLAN_ENCRYPTION_KEY oder gespeicherten GeheimnissenDen Schlüssel der alten Instanz auf der neuen setzen und neu starten. Erst dann umschalten.
SMTP nicht erreichbarViele Anbieter sperren ausgehend Port 25 und 465. SMTP_PORT=587 mit STARTTLS verwenden.
Nach Übernehmen passiert nichtsDie Übernahme braucht einen Neustart der neuen Instanz. Im Protokoll muss Instanz wiederhergestellt stehen.
Die Seite der alten Instanz zeigt „schreibgeschützt“, obwohl der Umzug abgebrochen wurdeInstanz umziehen → Schreibschutz aufheben.

Beispiel: Hetzner Cloud

Ein konkreter Weg vom Heimserver auf einen Server bei Hetzner, mit Docker Compose und Caddy. Namen und Preise der Tarife ändern sich – maßgeblich ist die Hetzner Console.

Server

EinstellungEmpfehlung
TypCAX21 (Arm64, 4 vCPU, 8 GB RAM) oder CX32 (x86, 4 vCPU, 8 GB RAM) bzw. der aktuelle Nachfolger. 4 GB reichen für kleine Teams; die Texterkennung gescannter PDFs braucht kurzzeitig CPU, lokale KI (Ollama) deutlich mehr. Das Image gibt es für linux/arm64 und linux/amd64, beide Typen passen.
StandortFalkenstein (fsn1) oder Nürnberg (nbg1) – dort gibt es auch Object Storage.
ImageUbuntu 24.04
NetzwerkÖffentliche IPv4 und IPv6. Eine IPv4-Adresse behalten: Nicht jede Registry und jeder Mailserver ist über IPv6 erreichbar.
SSH-KeyEigenen öffentlichen Schlüssel hinterlegen; Anmeldung mit Passwort gar nicht erst nutzen.
FirewallEine Hetzner Cloud Firewall anlegen und zuweisen: eingehend TCP 22 nur von deiner Adresse (oder deinem VPN), TCP 80 und 443 sowie UDP 443 (HTTP/3) von überall. Docker umgeht ufw auf dem Server; die Cloud Firewall davor greift trotzdem.
BackupsBackups des Servers einschalten (Aufpreis auf den Serverpreis): tägliche Abbilder der ganzen Platte, zusätzlich zu Flowplans eigenen Sicherungen.

Object Storage als S3

  1. In der Hetzner Console Object Storage → Bucket erstellen, Standort wie der Server (z. B. Falkenstein), Sichtbarkeit privat. Der Name muss eindeutig sein, z. B. flowplan-<dein-name>.
  2. Sicherheit → S3-Zugangsdaten → Zugangsdaten erstellen. Das Secret wird nur einmal angezeigt.
  3. In die .env:
S3_BUCKET=flowplan-beispiel
S3_ENDPOINT=https://fsn1.your-objectstorage.com
S3_REGION=fsn1
S3_ACCESS_KEY_ID=<Access Key>
S3_SECRET_ACCESS_KEY=<Secret Key>
S3_PREFIX=flowplan

Endpoint und Region folgen dem Standort: https://<Standort>.your-objectstorage.com mit fsn1 (Falkenstein), nbg1 (Nürnberg) oder hel1 (Helsinki) als S3_REGION. Mit FLOWPLAN_ENCRYPTION_KEY liegen Dateien und Sicherungen dort verschlüsselt; die Litestream-Kopie nicht (siehe Litestream und Verschlüsselung). Object Storage wird monatlich abgerechnet, mit einem Grundpreis, der ein Kontingent enthält – die aktuellen Preise stehen bei Hetzner.

Docker, Flowplan und Caddy

Docker nach der offiziellen Anleitung für Ubuntu installieren (docs.docker.com/engine/install/ubuntu (öffnet in neuem Tab)), dann:

mkdir -p /opt/flowplan && cd /opt/flowplan
curl -o .env https://raw.githubusercontent.com/yannicschuller/flowplan/main/.env.example
# compose.yaml und Caddyfile von unten anlegen, .env ausfüllen
docker compose up -d

compose.yaml:

# Flowplan mit Caddy davor (HTTPS von Let's Encrypt). Genau eine Instanz (SQLite).
services:
  flowplan:
    image: ghcr.io/yannicschuller/flowplan:${FLOWPLAN_VERSION:-latest}
    env_file: .env
    environment:
      FLOWPLAN_DATA_DIR: /app/data
      # Caddy ist der eine Proxy davor und setzt X-Forwarded-For.
      FLOWPLAN_TRUSTED_PROXIES: "1"
    volumes:
      - flowplan-data:/app/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 30s
      timeout: 5s
      start_period: 20s
      retries: 3

  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    environment:
      FLOWPLAN_DOMAIN: ${FLOWPLAN_DOMAIN}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy-data:/data
      - caddy-config:/config
    depends_on:
      - flowplan
    restart: unless-stopped

volumes:
  flowplan-data:
  caddy-data:
  caddy-config:

Caddyfile:

{$FLOWPLAN_DOMAIN} {
	encode zstd gzip
	reverse_proxy flowplan:3000
}

In der .env zusätzlich zu den Werten der alten Instanz:

FLOWPLAN_DOMAIN=flowplan.example.org
APP_URL=https://flowplan.example.org
# SMTP: Hetzner sperrt für neue Konten ausgehend Port 25 und 465 – 587 mit STARTTLS nehmen.
SMTP_PORT=587
SMTP_SECURE=false
# Nur für den Umzug, wenn der Heimserver nur im LAN/VPN erreichbar ist:
# FLOWPLAN_MOVE_ALLOW_PRIVATE=true

Für eine vorübergehende Adresse während des Umzugs FLOWPLAN_DOMAIN=neu.flowplan.example.org und die passende APP_URL setzen; nach Übernehmen beide auf die endgültige Domain ändern und mit docker compose up -d neu starten – derselbe Neustart übernimmt den Umzug. Caddy kann auch beide Namen bedienen: {$FLOWPLAN_DOMAIN}, neu.flowplan.example.org { … }.

Lieber Kubernetes? Das Helm-Chart aus dem Repository läuft auch auf einem einzelnen Server (etwa mit k3s); der Umzug geht dann über die Oberfläche oder kubectl exec … node /app/move.mjs (oben).

Ablauf mit dem Heimserver

  1. Einen Tag vorher die TTL des DNS-Eintrags auf 300 Sekunden senken.
  2. Den Hetzner-Server wie oben einrichten, mit denselben Variablen wie zu Hause (Schlüssel!), und mit docker compose up -d starten; das erste Konto anlegen.
  3. Zu Hause Umzug vorbereiten, auf dem Hetzner-Server Von anderer Instanz übernehmen mit der öffentlichen Adresse des Heimservers (oder seiner VPN-Adresse mit FLOWPLAN_MOVE_ALLOW_PRIVATE=true).
  4. Vorabprüfung, bis keine Fehler bleiben. Quelle schreibschützen und letzten Stand holen, Übernehmen, docker compose restart flowplan.
  5. A- und AAAA-Eintrag auf die Adressen des Hetzner-Servers stellen, Portweiterleitung am Router entfernen.
  6. Danach prüfen, nach ein paar Tagen aufräumen.

Auf GitHub bearbeiten