Deployment
Simmetric Chat ist air-gap capable und local-first. Fünf Deployment-Ziele: Docker Compose multi-container (empfohlen für Produktion), Single-Container all-in-one (Air-Gap-Umgebungen), verwalteter Coolify-Stack, Dev-Override (Hot-Reload auf Docker) und De…
Simmetric Chat ist air-gap capable und local-first. Fünf Deployment-Ziele: Docker Compose multi-container (empfohlen für Produktion), Single-Container all-in-one (Air-Gap-Umgebungen), verwalteter Coolify-Stack, Dev-Override (Hot-Reload auf Docker) und Desktop Tauri. Alle Artefakte leben in docker/; die Desktop-Shell in src-tauri/. Die auf GHCR veröffentlichten Images sind nur amd64 (linux/amd64 - die via QEMU emulierten arm64-Builds hingen; auf arm64 macht man einen lokalen Self-Build vom nativen Host). Alle Container nutzen wget-Healthchecks (--spider): server GET /api/health, collector GET /api/health auf 3210, widget GET /health auf 3211, Postgres pg_isready, Redis redis-cli ping.
Voraussetzungen
- Node.js ≥ 24, pnpm 11.24.0, PostgreSQL 16.
- Für lokales Embedding: ~2 GB RAM pro
all-MiniLM-L6-v2(Xenova, CPU). - Für lokales LLM: Ollama mit vorab gepullten Modell(en) (
gemma4:latestStandard). - Für Vision-OCR: Ollama mit Vision-Modell (
glm-ocr:latestStandard).
Docker Compose (Produktion)
Das Produktions-Compose (docker/docker-compose.yml) definiert 6 aktive Services: frontend (nginx, :80/:443), server (:3000), collector (:3210), widget (:3211), postgres (16, Image pgvector/pgvector:pg16), redis (7-alpine, optionaler Scaling-Cache). ollama und qdrant sind standardmäßig deaktiviert (kommentierte Blöcke: auskommentieren + OLLAMA_BASE_URL / VECTOR_DB_PROVIDER=qdrant setzen, um sie zu nutzen).
cp .env.example .env
# Bearbeite .env: JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, DATABASE_URL, LICENSE_KEY (wenn Enterprise)
docker compose -f docker/docker-compose.yml up -dKritische Produktions-Envs (siehe 03 - Configuration):
JWT_SECRET- erforderlich, kryptographisches Material (leitetENCRYPTION_KEYab wenn unset).COLLECTOR_SECRET- erforderlich, muss zwischen Server und Collector übereinstimmen.WIDGET_API_KEY- erforderlich für das Widget, muss zwischen Widget und Server übereinstimmen.DATABASE_URL- PostgreSQL 16.LICENSE_KEY+LICENSE_SECRET- nur Enterprise.ENCRYPTION_KEY(base64 32 Byte) - empfohlen für persistente Data-at-Rest überJWT_SECRET-Rotationen hinaus.
Key-Rotation: Setze LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32-Byte), um die Entschlüsselbarkeit alter Backups/Daten während der Rotation zu erhalten. Es gibt keinen automatischen Re-Encryption-Job: manuelle Prozedur decrypt-old → re-encrypt-new.Auto-Provisioning der Keys (Server-Entrypoint)
Der Produktions-Entrypoint (docker/entrypoint-server.sh) führt bei jedem Boot aus: Provisioning von ENCRYPTION_KEY und API_KEY_HMAC_SECRET mit der Priorität operator-supplied Wert > im Volume server-storage persistierter Wert > einmal generiert und persistiert (nie auf bestehendem Material neu generiert); dann prisma migrate deploy + Seed und der Server-Start. Die Dev-Konfigurationen (docker-compose.dev.yml) überspringen das Provisioning und behalten den scrypt-Fallback.
Volumes & Persistenz
- PostgreSQL: dediziertes Volume (
pgdata). - LanceDB:
${STORAGE_PATH}/vectors/lancedb(Collector). - File Storage:
${STORAGE_PATH}(Collector, Dokumente/Avatare/Uploads). - Backup: pro-Job konfigurierte Destinationen (Disk/S3/Dropbox/...).
Health Check nach dem Deploy
Die Container verifizieren sich selbst via wget (siehe Intro). Äquivalente manuelle Checks:
curl http://localhost:3000/api/health
# { "status": "ok", "checks": { "database": "ok", "collector": "ok", "disk": "ok" } }
curl http://localhost:3210/api/health # collector
curl http://localhost:3211/health # widgetSingle-Container all-in-one
docker/Dockerfile baut ein einziges Image, das von supervisord überwacht wird und PostgreSQL 16 (pgvector offline für Air-Gap kompiliert), Server, Collector und Widget ausführt. Es exponiert 3000/3210/3211, nutzt DATABASE_URL auf localhost, Healthcheck auf /api/health. Gedacht für Air-Gap-/Offline-/Demo-Umgebungen: Die Default-Envs sind Platzhalter - überschreibe sie via .env oder -e.
Coolify
docker/docker-compose.coolify.yml + docker/nginx.coolify.conf automatisieren den Image-Build, das interne Networking, Volumes, Healthchecks und den Mount des Enterprise-Plugins (absoluter Host-Pfad ${ENTERPRISE_PLUGIN_PATH:-/opt/simmetric-enterprise}). Die erforderlichen Secrets nutzen die Syntax :? (Coolify verweigert das Deployment wenn sie fehlen): JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, POSTGRES_PASSWORD, APP_URL, ALLOWED_ORIGINS. Unterschiede zum Basis-Compose: kein container_name, kein Host-Port auf den Apps (Ingress via Traefik, HTTP-only - TLS von Traefik terminiert), ENCRYPTION_KEY/API_KEY_HMAC_SECRET nicht interpoliert (im Volume auto-provisioniert).
Lokale Entwicklung
pnpm install
pnpm db:generate # Prisma Client (+ Fix Prisma/pnpm Symlink)
pnpm --filter server db:migrate # Migrationen anwenden
pnpm dev # turborepo: server + collector + widget + frontend parallelDetails in 10 - Development.
Dev-Override (Docker)
docker/docker-compose.dev.yml mountet die Quellen auf das Produktions-Compose für Hot-Reload (NODE_ENV=development). docker-compose.infra.yml startet nur Postgres/Qdrant, während die App auf dem Host läuft.
Desktop (Tauri)
src-tauri/ - Desktop-App, die das Frontend wrappt. Build mit pnpm tauri build. Konfiguriere src-tauri/tauri.conf.json für Remote-Server-URL oder lokales Bundle.
Reverse Proxy (Nginx)
Wichtige Punkte:
- SSE: Buffering deaktivieren (
proxy_buffering off;,X-Accel-Buffering: nowird bereits vom Server/Widget gesendet). - Timeout: langsame lokale LLMs → hoher
proxy_read_timeout(≥ 600s, der Standard-Agent-Watchdog ist 10 min). - Upload:
client_max_body_size≥ 100 MB (Multer-Limit Dokumente). - CORS: Die Allowlist wird app-seitig verwaltet (
ALLOWED_ORIGINS); das Widget hat dynamisches Per-Origin-CORS (allowedOrigins).
Backup in Produktion
- Destination erstellen (
POST /api/backup-destinations). - Job erstellen (
POST /api/backup-jobs) mit Cronfrequency/time+retentionDays. - Verifizieren mit
POST /backup-destinations/:id/testund einem manuellen RunPOST /backup-jobs/:id/run. - Restore:
POST /api/backups/restore/:logId(Dry-Run empfohlen vorher:/restore/:logId/dry-run). Atomarität via psql--single-transaction.
Siehe 05 - Feature Guide § Backup.
Produktionssicherheit
- Ändere das Bootstrap-Admin-Passwort; setze
ALLOW_REGISTRATION=falsein Prod (Self-Registration geschlossen). DLP_ENABLEDStandard"true"in v0.22 - Redaction von Chat-Input/Output über 10 Built-in-Patterns (siehe 05 - Feature Guide); nutzeDLP_BYPASS_ROLES, um ausgewählte Rollen auszunehmen.- Aktiviere
audit_log_immutable(Enterprise) für Append-Only-Audit. - HTTPS am Reverse Proxy terminiert;
helmet-Header auf dem Server aktiv (für das Widget beim Embedding gelockert). - Rate Limits bereits konfiguriert (siehe 04 - API Reference § Rate limit): Das Chat-Limit wird jetzt vom Budget Tracker des Agenten verwaltet (Per-User-Concurrency, Wallclock, Token) plus das globale Schutznetz von 200 req/min.
Cross-Link
- Vollständige Envs: 03 - Configuration
- Entwicklung: 10 - Development
- Deploy-Troubleshooting: 12 - Troubleshooting