Back to docs
Guide 09

Deployment

Docker, air-gap, Tauri, backups, key rotation.

Simmetric Chat è air-gap capable e local-first. Tre modalità principali: Docker Compose (raccomandata), sviluppo locale (pnpm), desktop Tauri.

Prerequisiti

  • Node.js ≥ 20, pnpm ≥ 9, PostgreSQL 16.
  • Per embedding locale: ~2 GB RAM per all-MiniLM-L6-v2 (Xenova, CPU).
  • Per LLM locale: Ollama con modello(s) pre-pullati (gemma4:latest default).
  • Per OCR vision: Ollama con modello vision (glm-ocr:latest default).

Docker Compose (produzione)

Il repo include docker-compose.yml con servizi: server (:3000), collector (:3210), widget (:3211), frontend (:5173 o build statica), postgres (16), ollama.

cp .env.example .env
# Modifica .env: JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, DATABASE_URL, LICENSE_KEY (se Enterprise)
docker compose up -d --build

Env critici di produzione (vedi 03 — Configuration):

  • JWT_SECRET — obbligatorio, materiale critografico (deriva ENCRYPTION_KEY se unset).
  • COLLECTOR_SECRET — obbligatorio, deve matchare tra server e collector.
  • WIDGET_API_KEY — obbligatorio per widget, deve matchare tra widget e server.
  • DATABASE_URL — PostgreSQL 16.
  • LICENSE_KEY + LICENSE_SECRET — solo Enterprise.
  • ENCRYPTION_KEY (base64 32 byte) — consigliato per data-at-rest persistente oltre rotazioni di JWT_SECRET.

Rotazione chiavi: imposta LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32-byte) per mantenere decryptabilità dei backup/dati vecchi durante la rotazione. Non esiste job automatico di re-encryption: procedura manuale decrypt-old → re-encrypt-new.

Profili Compose

.env.example documenta --profile enterprise ma il compose non lo definisce esplicitamente come profilo separato — Enterprise si attiva via LICENSE_KEY, non via profilo. Verificare la versione corrente di docker-compose.yml prima di affidarsi a profili.

Volumi & persistenza

  • PostgreSQL: volume dedicato (postgres-data).
  • LanceDB: ${STORAGE_PATH}/vectors/lancedb (collector).
  • File storage: ${STORAGE_PATH} (collector, documenti/avatar/uploads).
  • Backup: destinazioni configurate per-job (disk/S3/Dropbox/...).

Health check post-deploy

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        # widget

Sviluppo locale

pnpm install
pnpm db:setup        # crea DB, migra, seed admin
pnpm dev             # turborepo: server + collector + widget + frontend paralleli

Dettagli in 10 — Development.

Desktop (Tauri)

packages/src-tauri — app desktop che wrappa il frontend. Build con pnpm tauri:build. Configura src-tauri/tauri.conf.json per URL server remoto o bundle locale.

Reverse proxy (Nginx)

Punti chiave:

  • SSE: disabilitare buffering (proxy_buffering off;, X-Accel-Buffering: no già inviato dal server/widget).
  • Timeout: LLM locali lenti → proxy_read_timeout alto (≥ 600s, l'agent watchdog default è 10 min).
  • Upload: client_max_body_size ≥ 100 MB (limite multer documenti).
  • CORS: l'allowlist è gestita lato app (ALLOWED_ORIGINS); il widget ha CORS dinamico per-origin (allowedOrigins).

Backup in produzione

  1. Crea destinazione (POST /api/backup-destinations).
  2. Crea job (POST /api/backup-jobs) con cron frequency/time + retentionDays.
  3. Verifica con POST /backup-destinations/:id/test e un run manuale POST /backup-jobs/:id/run.
  4. Restore: POST /api/backups/restore/:logId (dry-run consigliato prima: /restore/:logId/dry-run). Atomicità via psql --single-transaction.

Vedi 05 — Feature Guide § Backup.

Sicurezza di produzione

  • Cambia password admin bootstrap; imposta ALLOW_REGISTRATION=false in prod.
  • DLP_ENABLED default false — abilita se gestisci PII (redaction input/output chat).
  • Abilita audit_log_immutable (Enterprise) per audit append-only.
  • HTTPS terminato al reverse proxy; header helmet attivi sul server (rilassati sul widget per embedding).
  • Rate limit già configurati (vedi 04 — API Reference § Rate limit); valuta di alzarli per Enterprise (chat LLM 100/min).

Cross-link