Voltar para a documentação
Guia 09

Deploy

Simmetric Chat é air-gap capable e local-first. Cinco targets de deploy: Docker Compose multi-container (recomendado para produção), container único all-in-one (ambientes air-gapped), stack gerido Coolify, override dev (hot-reload sobre Docker) e desktop…

4 min de leitura

Simmetric Chat é air-gap capable e local-first. Cinco targets de deploy: Docker Compose multi-container (recomendado para produção), container único all-in-one (ambientes air-gapped), stack gerido Coolify, override dev (hot-reload sobre Docker) e desktop Tauri. Todos os artefatos vivem em docker/; o shell desktop em src-tauri/. As imagens publicadas no GHCR são apenas amd64 (linux/amd64 - os builds arm64 emulados via QEMU bloqueavam; em arm64 faz-se self-build local a partir do host nativo). Todos os containers usam healthcheck wget (--spider): server GET /api/health, collector GET /api/health em 3210, widget GET /health em 3211, Postgres pg_isready, Redis redis-cli ping.

Pré-requisitos

  • Node.js ≥ 24, pnpm 11.24.0, PostgreSQL 16.
  • Para embedding local: ~2 GB RAM por all-MiniLM-L6-v2 (Xenova, CPU).
  • Para LLM local: Ollama com modelo(s) pré-puxados (gemma4:latest por defeito).
  • Para OCR vision: Ollama com modelo vision (glm-ocr:latest por defeito).

Docker Compose (produção)

O compose de produção (docker/docker-compose.yml) define 6 serviços ativos: frontend (nginx, :80/:443), server (:3000), collector (:3210), widget (:3211), postgres (16, imagem pgvector/pgvector:pg16), redis (7-alpine, cache de scaling opcional). ollama e qdrant estão desativados por defeito (blocos comentados: descomenta + define OLLAMA_BASE_URL / VECTOR_DB_PROVIDER=qdrant para os usar).

bash
cp .env.example .env
# Edita .env: JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, DATABASE_URL, LICENSE_KEY (se Enterprise)
docker compose -f docker/docker-compose.yml up -d

Env críticos de produção (ver 03 - Configuration):

  • JWT_SECRET - obrigatório, material criptográfico (deriva ENCRYPTION_KEY se unset).
  • COLLECTOR_SECRET - obrigatório, deve casar entre server e collector.
  • WIDGET_API_KEY - obrigatório para widget, deve casar entre widget e server.
  • DATABASE_URL - PostgreSQL 16.
  • LICENSE_KEY + LICENSE_SECRET - apenas Enterprise.
  • ENCRYPTION_KEY (base64 32 byte) - recomendado para persistência data-at-rest além de rotações de JWT_SECRET.
Rotação de chaves: define LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32-byte) para manter a decryptabilidade de backups/dados antigos durante a rotação. Não existe job automático de re-encryption: procedimento manual decrypt-old → re-encrypt-new.

Auto-provisioning de chaves (entrypoint server)

O entrypoint de produção (docker/entrypoint-server.sh) executa a cada boot: provisioning de ENCRYPTION_KEY e API_KEY_HMAC_SECRET com precedência valor operator-supplied > valor persisitido no volume server-storage > gerado uma vez e persistido (nunca regenerado sobre material existente); depois prisma migrate deploy + seed e o arranque do servidor. As configurações dev (docker-compose.dev.yml) saltam o provisioning e mantêm o fallback scrypt.

Volumes & persistência

  • PostgreSQL: volume dedicado (pgdata).
  • LanceDB: ${STORAGE_PATH}/vectors/lancedb (collector).
  • File storage: ${STORAGE_PATH} (collector, documentos/avatar/uploads).
  • Backup: destinos configurados por-job (disk/S3/Dropbox/...).

Health check pós-deploy

Os containers auto-verificam-se via wget (ver intro). Checks manuais equivalentes:

bash
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

Container único all-in-one

docker/Dockerfile constrói uma única imagem supervisionada por supervisord que executa PostgreSQL 16 (pgvector compilado offline para air-gap), server, collector e widget. Expõe 3000/3210/3211, usa DATABASE_URL em localhost, healthcheck em /api/health. Pensada para ambientes air-gapped/offline/demo: os env por defeito são placeholder - sobrescreve-os via .env ou -e.

Coolify

docker/docker-compose.coolify.yml + docker/nginx.coolify.conf automatizam build das imagens, networking interno, volumes, healthchecks e o mount do plugin enterprise (path host absoluto ${ENTERPRISE_PLUGIN_PATH:-/opt/simmetric-enterprise}). Os segredos requeridos usam a sintaxe :? (o Coolify recusa o deploy se faltarem): JWT_SECRET, COLLECTOR_SECRET, WIDGET_API_KEY, POSTGRES_PASSWORD, APP_URL, ALLOWED_ORIGINS. Diferenças do compose base: sem container_name, sem porta host nas apps (ingress confiado ao Traefik, HTTP-only - TLS terminado pelo Traefik), ENCRYPTION_KEY/API_KEY_HMAC_SECRET não interpoladas (auto-provisionadas no volume).

Desenvolvimento local

bash
pnpm install
pnpm db:generate      # Prisma client (+ fix symlink Prisma/pnpm)
pnpm --filter server db:migrate   # aplica as migrações
pnpm dev              # turborepo: server + collector + widget + frontend em paralelo

Detalhes em 10 - Development.

Override dev (Docker)

docker/docker-compose.dev.yml monta as fontes sobre o compose de produção para hot-reload (NODE_ENV=development). docker-compose.infra.yml arranca apenas Postgres/Qdrant com a app em execução no host.

Desktop (Tauri)

src-tauri/ - app desktop que wrappea o frontend. Build com pnpm tauri build. Configura src-tauri/tauri.conf.json para URL server remota ou bundle local.

Reverse proxy (Nginx)

Pontos-chave:

  • SSE: desativar buffering (proxy_buffering off;, X-Accel-Buffering: no já enviado pelo server/widget).
  • Timeout: LLM locais lentos → proxy_read_timeout alto (≥ 600s, o agent watchdog default é 10 min).
  • Upload: client_max_body_size ≥ 100 MB (limite multer documentos).
  • CORS: a allowlist é gerida do lado app (ALLOWED_ORIGINS); o widget tem CORS dinâmico per-origem (allowedOrigins).

Backup em produção

  1. Cria destino (POST /api/backup-destinations).
  2. Cria job (POST /api/backup-jobs) com cron frequency/time + retentionDays.
  3. Verifica com POST /backup-destinations/:id/test e um run manual POST /backup-jobs/:id/run.
  4. Restore: POST /api/backups/restore/:logId (dry-run recomendado antes: /restore/:logId/dry-run). Atomicidade via psql --single-transaction.

Ver 05 - Feature Guide § Backup.

Segurança de produção

  • Muda a password admin bootstrap; define ALLOW_REGISTRATION=false em prod (self-registration fechada).
  • DLP_ENABLED default "true" em v0.22 - redaction input/output chat sobre 10 padrões built-in (ver 05 - Feature Guide); usa DLP_BYPASS_ROLES para isentar roles selecionados.
  • Ativa audit_log_immutable (Enterprise) para audit append-only.
  • HTTPS terminado no reverse proxy; headers helmet ativos no server (relaxados no widget para embedding).
  • Rate limit já configurados (ver 04 - API Reference § Rate limit): o limite chat é agora gerido pelo budget tracker do agente (concorrência per-utilizador, wallclock, token) mais a rede de proteção global 200 req/min.