4 Server und Instanzen
Daniel Heinze | ho.Systeme GmbH + Co. KG edited this page 2026-10-25 16:25:51 +01:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Server und Instanzen

Auf einem Server läuft jede Instanz als eigener Docker-Container mit eigenen Daten, eigener Ablage, eigenem Erscheinungsbild und eigener Subdomain. Alle laufen aus demselben Image hinter einem gemeinsamen Caddy, der HTTPS (Let's Encrypt) macht. Die App-Container sind nur im internen Docker-Netz immo-netz erreichbar.

Die Vorlagen liegen im Repo unter deploy/ (immo.sh, instanz.compose.yml, proxy/).

Aufbau auf dem Server

Was Wo (/opt/immobilien)
Code, gemeinsam für alle Instanzen (als /app eingehängt) app/
je Instanz: Einstellungen instanzen/<name>/instanz.env
je Instanz: Stammdaten, Ablage, Cache instanzen/<name>/daten/, ablage/, cache/
Proxy und je Instanz ein Eintrag proxy/Caddyfile, proxy/instanzen/<name>.caddy
Vorlage für einen Instanz-Container instanz.compose.yml
Verwaltung immo.sh

immo.sh

./immo.sh bauen                                   # Image aus app/ bauen
./immo.sh liste
./immo.sh anlegen kunde immo-kunde.example.de entra "Kunde Immobilien"
./immo.sh anlegen test immo-test.example.de passwort "Test" test < passwort.txt
./immo.sh start kunde              # starten bzw. nach Änderungen an der instanz.env neu starten
./immo.sh stopp kunde
./immo.sh umstellen kunde entra    # Anmeldeart wechseln (passwort: Passwort über stdin)
./immo.sh passwort test            # neues Passwort (über stdin), mindestens 12 Zeichen
./immo.sh notfall kunde [benutzer] # lokalen Administrator anlegen/zurücksetzen (Passwort über stdin)
./immo.sh entfernen test           # Container und Proxy-Eintrag weg, Daten bleiben liegen
./immo.sh aktualisieren            # Image neu bauen, alle Instanzen neu starten
./immo.sh auffrischen              # Node-/Alpine-Patches: neu bauen, nur bei Änderung neu starten, sonst Rückfall
./immo.sh zeitplan an [m h tag]    # auffrischen per cron, Vorgabe sonntags 04:30
./immo.sh zeitplan aus
./immo.sh proxy                    # Proxy starten bzw. Konfiguration neu laden

Zwei Arten des Zugangs je Instanz:

  • entra – die App meldet über Microsoft Entra ID an; hinein darf nur, wer in einer der freigegebenen Gruppen ist. Nach anlegen die ENTRA_*-Werte in der instanz.env eintragen und ./immo.sh start <name>.
  • passwort – Caddy fragt Benutzer und Passwort ab (bcrypt), die App selbst bleibt ohne Anmeldung.

Mehr dazu unter Anmeldung und Rollen.

instanz.env

IMMO_NAME=Kunde Immobilien
IMMO_URL=https://immo-kunde.example.de
IMMO_ANMELDUNG=entra            # oder: keine
IMMO_SITZUNG_GEHEIMNIS=…        # wird von immo.sh erzeugt
IMMO_SITZUNG_STUNDEN=12
ENTRA_TENANT_ID=
ENTRA_CLIENT_ID=
ENTRA_CLIENT_SECRET=
ENTRA_GRUPPEN=                  # Objekt-IDs der Gruppen, mehrere mit Komma

Ist ENTRA_CLIENT_SECRET gesetzt, wird es beim Start in die Einstellungen übernommen und neu verschlüsselt – hilfreich, wenn sich .cache/secret.key geändert hat.

Neuen Code einspielen

Aus der App: Unter Einstellungen → Update steht das Repository dieses Werkzeugs. „Update einspielen“ holt, was neu ist, und startet neu. Weil alle Instanzen app/ teilen, wirkt ein Update für alle – die übrigen starten von selbst nach, sobald bei ihnen nichts mehr läuft.

Von Hand:

tar -cf - --exclude=werkzeuge/startdaten.js Dockerfile .dockerignore package.json package-lock.json CHANGELOG.md server.js src public werkzeuge \
  | ssh root@<server> 'tar -xf - -C /opt/immobilien/app && /opt/immobilien/immo.sh aktualisieren'

Daten bleiben in beiden Fällen unberührt.

Wichtig: Das Update aus der App bringt nur neuen Code in app/, kein neues Image. Ändert sich das Dockerfile – zuletzt mit 0.32.0 (Texterkennung: poppler, Tesseract) –, auf dem Server einmal ./immo.sh aktualisieren ausführen. Bis dahin zeigt „Einstellungen → Dokumentenablage“, welche Programme fehlen.

Node.js und Pakete aktuell halten

Was Wie es auf den Server kommt
npm-Pakete (package-lock.json) mit dem Code – das Update aus der App führt danach npm install aus
Node-Patches und Alpine-Pakete (Sicherheitsupdates für Node, poppler, Tesseract …) Image neu bauen: ./immo.sh auffrischen, am besten nach Zeitplan
Caddy-Proxy (caddy:2-alpine) ebenfalls ./immo.sh auffrischen
neue Node-Hauptversion (24 → 26) bewusst: FROM im Dockerfile und das Image in .forgejo/workflows/ ändern, Tests abwarten, dann ./immo.sh aktualisieren

Das Dockerfile legt nur die Hauptversion fest (node:24-alpine, LTS bis April 2028); gebaut wird immer mit --pull, also mit dem neuesten Patch.

./immo.sh auffrischen

  1. merkt sich das laufende Image als immobilien-app:vorher,
  2. baut mit --pull neu – ist das Image unverändert, passiert sonst nichts,
  3. legt die Pakete neu an und startet die Instanzen neu,
  4. prüft je Instanz bis zu zwei Minuten /gesund,
  5. antwortet eine nicht: zurück auf vorher, Instanzen neu starten, Ende mit Fehlercode,
  6. dann der Proxy: neuestes Caddy 2 holen; bei neuem Image Proxy neu starten und je Instanz https://<domain>/gesund über den Proxy abrufen (2xx, 3xx und 401 gelten als erreichbar),
  7. kommt eine Domain nicht an: zurück auf das vorige Caddy-Image (immo-caddy:vorher), festgehalten in proxy/.env, bis ein späterer Lauf klappt.

Dafür muss proxy/docker-compose.yml die Fassung mit image: ${CADDY_IMAGE:-caddy:2-alpine} sein (ab 0.34.0, aus app/deploy/proxy/ kopieren). Mit einer festen Version überspringt auffrischen den Proxy und meldet das im Protokoll.

Einrichten: ./immo.sh zeitplan an legt /etc/cron.d/immobilien-auffrischen an (sonntags 04:30); andere Zeit z. B. ./immo.sh zeitplan an 0 3 '*' für täglich 03:00. Protokoll: /var/log/immo-auffrischen.log. Wer bei Fehlern eine Mail möchte, trägt in der cron-Datei MAILTO=… ein (braucht einen Mailversand auf dem Server).

Überwachung: Der Workflow Tests (.forgejo/workflows/tests.yml) läuft bei jedem Push und montags früh: Tests auf Node 24 und npm audit ab „high“. Ist der Montagslauf rot, gibt es eine neue Lücke in einem Paket – npm audit fix, testen, committen; das Update aus der App bringt es auf den Server.

Unterschiede zum lokalen Betrieb

  • Texterkennung über poppler und Tesseract im Image statt über Windows; der Volltext-Lauf liest die Ablage von selbst.
  • Die Ablage ist eine eigene Kopie; mit Dropbox oder Google Drive bleibt sie über den Cloud-Abgleich in Gleichstand.