- Shell 67.3%
- Makefile 16.4%
- HTML 16.3%
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>
|
||
|---|---|---|
| agents | ||
| authentik/blueprints | ||
| chat | ||
| docs | ||
| landing | ||
| monitoring/gatus | ||
| scripts | ||
| traefik | ||
| traefik-standalone | ||
| .env.example | ||
| .gitignore | ||
| .new_user_credentials_ | ||
| docker-compose.local.yml | ||
| docker-compose.yml | ||
| Makefile | ||
| README.md | ||
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 statszeigt >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:
- Authentik: http://localhost:9000
- Ollama: http://localhost:11434
- Gatus: http://localhost:3011
2. VPS einrichten (einmalig)
-
Hetzner CX22 bestellen, Ubuntu 24.04
-
SSH-Key auf root deployen
-
Bootstrap:
ssh root@<server-ip> 'bash -s' < scripts/bootstrap.shInstalliert Docker, härtet SSH, legt
deploy-User und/opt/demosan, aktiviert UFW + fail2ban + Swap. -
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):
authentik/blueprints/NN-<demo>.yamlals Kopie von10-gatus.yamlanlegen,external_host+ Provider/Application-Namen anpassen.cookie_domainnicht ändern — bleibtdev.ki-ohne-umweg.de, damit der Session-Cookie über alle Demo-Subdomains hinweg gilt (einmal einloggen → alle Demos offen).- Provider in
99-embedded-outpost.yamlunterproviders:ergänzen (sonst bleibt die M2M-Liste lückenhaft — Blueprints overriden die Liste, nicht append). 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.2gepinnt — 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:
- 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.
- Cold-Start-Latenz: Beim allerersten Request einer neuen Subdomain dauert es 5–10 Sekunden, bis das Cert provisioniert ist.
- Certificate Transparency Logs: Jede ausgestellte Cert-Subdomain landet öffentlich in CT-Logs (
crt.sh). Wer nach*.dev.ki-ohne-umweg.desucht, 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):
- Zone zu Hetzner DNS Console (
dns.hetzner.com) migrieren — gleicher Hetzner-Account, kostenlos, Records lassen sich automatisch importieren. Danach Nameserver beim Registrar aufhydrogen/helium/oxygen.ns.hetzner.comumstellen, API-Token erstellen, Traefik aufprovider: hetznermit DNS-Challenge umstellen. - 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:httpChallenge→dnsChallengemitprovider: <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 (1–24 h, in der Praxis meist deutlich schneller).