No description
  • Shell 67.3%
  • Makefile 16.4%
  • HTML 16.3%
Find a file
Daniel Schmitz d70adb707a feat(mockups): hermes-publish-pipeline + demos→dev domain migration
Mockups-Hosting:
- Neuer nginx-Service 'mockups' (Volume /srv/mockups, kein Authentik,
  noindex via security-headers)
- scripts/publish-mockup.sh — Helper für Hermes-Agents:
  Slug+Hash, rsync, .meta.json, gibt URL auf stdout zurück
- scripts/render-mockups-index.sh — generiert Hub-Seite
  (sortiert nach created_at)
- scripts/setup-mockups-server.sh — einmalig auf Server, idempotent
- docs/MOCKUPS.md — Architektur + Workflow

Domain-Migration demos→dev:
- Erste Hierarchie-Ebene umbenannt:
    *.demos.ki-ohne-umweg.de → *.dev.ki-ohne-umweg.de
    demos.ki-ohne-umweg.de   → dev.ki-ohne-umweg.de  (apex/landing)
- Betroffene Files: .env.example, docker-compose.yml, README.md,
  authentik/blueprints/0[5-9]*.yaml + 10-gatus + 11-chat,
  monitoring/gatus/config.yml, scripts/{bootstrap,preflight}.sh,
  traefik-standalone/config/dynamic/authentik-outpost.yml
- Cookie-Domain ändert sich → bestehende Sessions invalid

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 12:52:55 +02:00
agents fix: orphaned _shared entfernt, .env.example-Kommentare vereinheitlicht 2026-05-09 16:34:09 +02:00
authentik/blueprints feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
chat add chat interface to test local models 2026-04-12 01:02:14 +02:00
docs feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
landing add minimal landing page that will later server as an overview for different demos 2026-04-11 23:22:02 +02:00
monitoring/gatus feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
scripts feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
traefik initial commit: add initial setup for demo vps 2026-04-11 17:08:24 +02:00
traefik-standalone feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
.env.example feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
.gitignore feat: Agents-Makefile + .gitignore 2026-05-09 16:30:55 +02:00
.new_user_credentials_ add chat interface to test local models 2026-04-12 01:02:14 +02:00
docker-compose.local.yml initial commit: add initial setup for demo vps 2026-04-11 17:08:24 +02:00
docker-compose.yml feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00
Makefile feat: demos nutzt externes proxy-Netz, Traefik ausgelagert 2026-05-09 16:26:47 +02:00
README.md feat(mockups): hermes-publish-pipeline + demos→dev domain migration 2026-05-13 12:52:55 +02:00

Demo VPS — dev.ki-ohne-umweg.de

Schlanke Infrastruktur für Kunden-Demos. Eigenständig vom Ops-Server.

Stack

Service Zweck Memory
traefik Reverse Proxy, Wildcard-TLS via Hetzner DNS-Challenge 128M
postgres DB für Authentik 256M
redis Cache für Authentik 64M
authentik-server SSO / Identity Provider (Web UI + API) 1024M
authentik-worker SSO Background Jobs 1024M
ollama Lokales LLM-Backend für alle Demos 4G
gatus Uptime-Monitoring + Telegram-Alerts 64M

Gesamtbedarf: ~6,5 GB. Auf einem CX22 (8 GB) bleiben ~1,3 GB für 1 gleichzeitigen Demo-Container + OS. Für mehr parallele Demos: CX32 (16 GB) oder Ollama-Limit reduzieren (3 GB reicht für qwen2.5:3b, aber knapp).

Wichtig: Authentik 2026.x braucht mehr RAM als frühere Releases (Python 3.14, Enterprise-Module). Die alten 768M/512M führen zu einem stummen Worker-Stall: die Container bleiben "healthy", aber Dramatiq-Tasks landen in der Queue ohne je ausgeführt zu werden → Blueprints werden nicht angewendet, Applications erscheinen nicht in der UI. Symptom: docker stats zeigt >90 % MemPerc bei authentik-server/worker.

Ablauf

1. Lokal vorbereiten

make init                       # .env mit Random-Secrets erzeugen
# DEPLOY_HOST und HETZNER_DNS_API_TOKEN manuell eintragen
make local-up                   # Smoke-Test ohne DNS/TLS

Lokal erreichbar:

2. VPS einrichten (einmalig)

  1. Hetzner CX22 bestellen, Ubuntu 24.04

  2. SSH-Key auf root deployen

  3. Bootstrap:

    ssh root@<server-ip> 'bash -s' < scripts/bootstrap.sh
    

    Installiert Docker, härtet SSH, legt deploy-User und /opt/demos an, aktiviert UFW + fail2ban + Swap.

  4. DNS setzen — vor dem ersten Deploy (sonst schlägt die HTTP-01-Challenge fehl):

    • A *.dev.ki-ohne-umweg.de → <server-ip>
    • A dev.ki-ohne-umweg.de → <server-ip>

    Der Wildcard-A-Record sorgt dafür, dass jede neue Demo-Subdomain automatisch auf den Server zeigt — Traefik holt sich beim ersten Request dann das passende Cert.

3. Deployen

make deploy-restart             # rsync + Stack starten (lädt .env beim ersten Mal)
make pull-model                 # qwen2.5:3b auf den Server laden (paar Minuten)

make preflight erst nach Schritt 4 ausführen — der Status-Endpoint hängt hinter authentik@file, und der Gatus-Provider wird erst durch den Blueprint angelegt, sobald Authentik gestartet ist und der akadmin-User existiert.

4. Authentik einrichten

Provider, Applications und Outpost-Bindings werden per Blueprint deklarativ verwaltet — siehe authentik/blueprints/. Die Files werden beim Start in den authentik-worker gemountet und automatisch angewendet.

Der akadmin-User wird beim ersten Start automatisch aus AUTHENTIK_BOOTSTRAP_* in .env angelegt — kein initial-setup-Flow im Browser mehr nötig. Danach picked der Worker die Blueprints auf und legt gatus-provider + Gatus-Application an und bindet sie an den Embedded Outpost.

Login unter https://auth.dev.ki-ohne-umweg.de/ mit akadmin + AUTHENTIK_BOOTSTRAP_PASSWORD aus .env. Bootstrap-Passwort kann im Profil frei geändert werden; AUTHENTIK_BOOTSTRAP_TOKEN ist ein langlebiger Admin-API-Key für spätere Automatisierung. Status der Blueprints im Admin-UI unter System → Blueprints prüfen (sollte auf "successful" stehen).

Optional im Admin-UI:

  • Für selektiven Zugriff: Gruppe (demo-<name>-users) + Policy "User in Gruppe" anlegen und an die Application binden.
  • Demo-Kunden als User anlegen und in die passenden Gruppen stecken.

Neue Demo absichern (rein Terminal, kein Browser-Klick):

  1. authentik/blueprints/NN-<demo>.yaml als Kopie von 10-gatus.yaml anlegen, external_host + Provider/Application-Namen anpassen. cookie_domain nicht ändern — bleibt dev.ki-ohne-umweg.de, damit der Session-Cookie über alle Demo-Subdomains hinweg gilt (einmal einloggen → alle Demos offen).
  2. Provider in 99-embedded-outpost.yaml unter providers: ergänzen (sonst bleibt die M2M-Liste lückenhaft — Blueprints overriden die Liste, nicht append).
  3. make deploy-restart → Worker applied die Änderung.

SSO-Verhalten: Alle Demos laufen im forward_domain-Mode mit gemeinsamem cookie_domain. Ein Login bei Demo A legt den Cookie für das gesamte dev.ki-ohne-umweg.de — Demo B prüft nur noch den Cookie. Wer pro Demo getrennten Zugriff will, bindet Policies/Gruppen an die Application in Authentik (nicht an den Provider) — der Cookie authentifiziert, die Application-Policy autorisiert.

ssh deploy@<ip> 'cd /opt/demos && make preflight'   # Health-Check (jetzt sollte alles grün sein)

Pattern: Eine neue Demo deployen

Jede Demo lebt in einem eigenen git-Repo und bringt ihren eigenen docker-compose.yml mit. Die Demo joint die externen Netzwerke des Demo-VPS:

services:
  my-demo:
    image: ...
    networks:
      - demos_proxy           # Traefik kommt rein
      - demos_backend         # Ollama als http://ollama:11434 erreichbar
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=demos_proxy"
      - "traefik.http.routers.my-demo.rule=Host(`mydemo.dev.ki-ohne-umweg.de`)"
      - "traefik.http.routers.my-demo.tls=true"
      - "traefik.http.routers.my-demo.tls.certresolver=letsencrypt"
      - "traefik.http.routers.my-demo.middlewares=authentik@file,security-headers@file,rate-limit@file"
      - "traefik.http.services.my-demo.loadbalancer.server.port=<port>"
    deploy:
      resources:
        limits:
          memory: 512M        # PFLICHT — siehe Memory-Tabelle oben

networks:
  demos_proxy:
    external: true
  demos_backend:
    external: true

Regel: Jeder Demo-Container muss ein Memory-Limit haben. Richtwerte: n8n 512M, Postgres 256M, Mailpit 128M, Custom Frontends 256M.

Wenn die Demo Auth braucht, dann in Authentik eine neue Application + Proxy Provider anlegen — die Traefik-Middleware authentik@file ist im Demo-VPS-Stack schon konfiguriert, mehr brauchst du nicht.

Make-Targets

make init             .env mit sicheren Passwörtern generieren
make local-up         Stack lokal starten (Ports auf 127.0.0.1)
make local-down       Lokalen Stack stoppen
make deploy           Auf VPS syncen (kein Restart)
make deploy-restart   Syncen + Stack neu starten
make pull-model       Default-Ollama-Modell auf VPS laden
make preflight        Health Check (auf Server ausführen)
make status           Container-Status
make logs SERVICE=…   Logs anschauen
make nuke             ALLES löschen inkl. Volumes

Verzeichnisstruktur

demo-vps/
├── docker-compose.yml          # Haupt-Stack
├── docker-compose.local.yml    # Lokale Port-Overrides
├── .env.example
├── Makefile
├── traefik/
│   ├── traefik.yml             # Traefik-Hauptconfig (DNS-Challenge)
│   └── dynamic/
│       └── middlewares.yml     # authentik, security-headers, rate-limit
├── authentik/
│   └── blueprints/             # Proxy Provider + Application + Outpost-Binding pro Demo
├── monitoring/
│   └── gatus/config.yml        # Uptime-Checks + Telegram-Alerts
├── scripts/
│   ├── bootstrap.sh            # VPS-Erstsetup
│   ├── deploy.sh               # rsync + restart
│   ├── preflight.sh            # Pre-Demo Health Check
│   ├── init-databases.sql      # Postgres-Init: authentik DB
│   └── init-authentik-user.sh  # Postgres-Init: authentik User
└── README.md

Notizen

  • Kein zentraler Log-Stack auf dem Demo-VPS (RAM-Spar). docker compose logs <service> für Ad-hoc-Debugging. Bei Bedarf später Loki/Grafana via Ops-Server.
  • Authentik-Version ist auf 2026.2 gepinnt — vor Updates Release Notes lesen.
  • Ollama-Modelle mit 4 GB Limit: qwen2.5:3b (bestes Deutsch), llama3.2:3b, phi-3-mini. 7B-Modelle passen nicht zuverlässig.

TLS-Strategie & geplante Migration

Aktuell läuft Traefik mit der HTTP-01-Challenge von Let's Encrypt — jede Subdomain holt sich beim ersten Request einzeln ein Cert. Vorteil: kein DNS-API-Token nötig. Nachteile, derer man sich bewusst sein sollte:

  1. Let's Encrypt Rate-Limit: 50 neue Hostnamen pro registrierter Domain pro 7 Tage. Reicht für realistische Demo-Use-Cases, kann bei vielen kurzlebigen Demos aber eng werden.
  2. Cold-Start-Latenz: Beim allerersten Request einer neuen Subdomain dauert es 510 Sekunden, bis das Cert provisioniert ist.
  3. Certificate Transparency Logs: Jede ausgestellte Cert-Subdomain landet öffentlich in CT-Logs (crt.sh). Wer nach *.dev.ki-ohne-umweg.de sucht, sieht alle Demo-Hostnamen, auch wenn sie nicht öffentlich verlinkt sind.

Geplante Migration: HTTP-01 → DNS-01 mit Wildcard

Sobald ausreichend Zeit für eine DNS-Migration ist, sollte auf DNS-01-Challenge mit Wildcard-Cert umgestellt werden. Damit fallen alle drei Nachteile weg.

Aktueller Blocker: Die Domain ki-ohne-umweg.de liegt auf Hetzner Robot DNS (alte NS: ns1.your-server.de, ns.second-ns.com, ns3.second-ns.de). Der Robot-DNS hat keine API, die Traefik unterstützt.

Migrationspfade (in Reihenfolge der Empfehlung):

  1. Zone zu Hetzner DNS Console (dns.hetzner.com) migrieren — gleicher Hetzner-Account, kostenlos, Records lassen sich automatisch importieren. Danach Nameserver beim Registrar auf hydrogen/helium/oxygen.ns.hetzner.com umstellen, API-Token erstellen, Traefik auf provider: hetzner mit DNS-Challenge umstellen.
  2. Zone zu Cloudflare migrieren — kostenlos, beste API, granulare Token-Permissions. Traefik nutzt dann provider: cloudflare.

Was zu ändern wäre nach der Migration:

  • traefik/traefik.yml: httpChallengednsChallenge mit provider: <hetzner|cloudflare>
  • docker-compose.yml: API-Token-Env-Variable an Traefik durchreichen, Wildcard-tls.domains-Labels am Authentik-Router setzen
  • .env.example + .env: API-Token-Variable ergänzen
  • Diesen README-Abschnitt entfernen

Migration sollte ausserhalb der Geschäftszeiten passieren wegen DNS-Propagation (124 h, in der Praxis meist deutlich schneller).