Files
chlova/docs/deploy.md
T
Kantin-Petit d824d16eed feat(infra): prêt au déploiement GitOps Portainer + Telegram optionnel (v0.32.0)
Compose de prod docker-compose.prod.yml (GitOps, sans env_file, réseau proxy
réel, certresolver letsencrypt) + runbook docs/deploy.md (Phase 1, users
chlova restreints Portainer/n8n). Surface Telegram rendue optionnelle pour un
déploiement UI-only ; garde assertHasSurface fail-closed. Typecheck + 78 tests
verts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016w5jRe87MGdd6AMvXQcHNi
2026-06-23 11:27:07 +02:00

6.6 KiB

Déploiement CHLOVA (Phase 1 — lecture seule, GitOps Portainer)

Procédure de mise en production réelle sur le homelab. Cible : environnement Portainer vps-pogoo-002 (endpoint 11), aux côtés de proxy (Traefik), n8n, jenkins.

Modèle de risque. Phase 1 = lecture seule : CHLOVA_PHASE=1, PORTAINER_READ_ONLY=true, MCP read-only filtré. Aucune écriture branchée. Les secrets ne transitent jamais par l'agent : ils sont saisis par l'opérateur dans les variables de stack Portainer (UI) — voir §4.

Vue d'ensemble

Brique Réseau Exposé ?
backend (API + SPA) chlova-internal + proxy Ouichlova.pogoo.app via Traefik/TLS
ollama (proxy cloud) chlova-internal + chlova-egress Non
mcp-portainer (sidecar) chlova-internal Non
socket-proxy (Docker RO) chlova-internal Non
n8n (MCP natif) proxy (existant) déjà exposé en n8n.pogoo.app

Compose de prod : infra/docker-compose.prod.yml. Build de l'image fait par Portainer sur le VPS (GitOps : clone du dépôt + docker compose build). Contexte de build = racine du dépôt.


1. Prérequis — dépôt git accessible au VPS

GitOps exige un remote que Portainer peut cloner. Choisir un hébergeur privé (GitHub privé, Gitea du homelab…), puis :

git remote add origin <URL_DEPOT_PRIVE>
git push -u origin main

Noter l'URL de clone (HTTPS) + des identifiants en lecture (PAT/deploy key) pour Portainer.

2. Prérequis — secrets & login fort (générés, jamais commités)

Générer le hash de mot de passe + secrets TOTP/JWT pour l'admin de l'UI :

cd orchestrator
npm run provision-auth -- <admin_user> '<mot_de_passe_fort>'

La commande imprime CHLOVA_ADMIN_PASSWORD_HASH, CHLOVA_TOTP_SECRET, CHLOVA_JWT_SECRET et un otpauth://… à scanner dans une app TOTP. Conserver ces valeurs pour l'étape 4 (UI Portainer). Ne pas les committer.

3. Prérequis — users restreints (chlova)

Le MCP Portainer n'expose pas la gestion d'utilisateurs/tokens : ces étapes se font dans les UI Portainer et n8n. Principe : CHLOVA n'accède qu'à ses ressources, avec des tokens à portée minimale.

3a. Portainer — user chlova + token

  1. Users → Add user : chlova, mot de passe fort. Non-administrateur.
  2. Environments → vps-pogoo-002 → Access : donner à chlova le rôle le plus bas suffisant. En CE, la granularité est par environnement (pas par stack) — l'accès se limite donc à ce seul environnement. (La restriction par-ressource fine nécessite l'édition Business ; à défaut, le verrou réel reste PORTAINER_READ_ONLY=true côté sidecar.)
  3. Se connecter en tant que chlovaMy account → Access tokens → Add token. Copier le token → ce sera PORTAINER_MCP_AUTH_TOKEN.

3b. n8n — projet + membre chlova

  1. Admin → Users : inviter/créer un utilisateur chlova.
  2. Projects → New project « CHLOVA » ; ajouter chlova comme membre. Y déplacer les workflows que CHLOVA doit voir (les autres restent invisibles).
  3. Settings → n8n API / MCP : activer le serveur MCP natif, générer le MCP Access Token scopé → ce sera MCP_N8N_AUTH_TOKEN. Endpoint interne : http://n8n:5678/mcp-server/http (backend sur réseau proxy).

4. Déploiement du stack (Portainer)

infra/docker-compose.prod.yml n'utilise aucun env_file : toutes les variables ci-dessous sont fournies comme variables d'environnement du stack Portainer (les secrets y sont saisis par l'opérateur, jamais par l'agent).

Variables de stack à renseigner

Variable Exemple / valeur Secret ?
CHLOVA_DOMAIN chlova.pogoo.app non
CHLOVA_PHASE 1 non
PORTAINER_READ_ONLY true non
OLLAMA_API_KEY clé Ollama cloud oui
OLLAMA_MODEL qwen3:cloud non
MCP_N8N_AUTH_TOKEN token MCP n8n (§3b) oui
PORTAINER_URL URL interne de l'API Portainer (cf. §4 note) non
PORTAINER_MCP_AUTH_TOKEN token user chlova (§3a) oui
CHLOVA_ADMIN_USER ex. kantin non
CHLOVA_ADMIN_PASSWORD_HASH (§2) oui
CHLOVA_TOTP_SECRET (§2) oui
CHLOVA_JWT_SECRET (§2) oui

PORTAINER_URL = URL publique du serveur Portainer. Topologie réelle : le serveur Portainer (portainer-ce) tourne sur l'hôte local, tandis que CHLOVA et son sidecar tournent sur vps-pogoo-002 (un autre hôte). Le sidecar ne peut donc pas joindre Portainer en interne : utiliser l'URL publique (la même que celle configurée pour le MCP portainer-pogoo), p. ex. https://<portainer>.pogoo.app. Pas de :9443 interne ici.

Procédure UI (recommandée — l'opérateur saisit les secrets)

Stacks → Add stack → Git repository :

  • Repository URL = remote de l'étape 1 ; Reference = refs/heads/main ; Compose path = infra/docker-compose.prod.yml.
  • Authentication = identifiants de lecture (§1).
  • Environment variables = tableau ci-dessus.
  • Deploy. Portainer clone, build l'image et lance le stack.

Procédure assistée (MCP)

CHLOVA peut créer le stack via StackCreateDockerStandaloneRepository une fois le remote prêt — mais les valeurs secrètes ne doivent pas transiter par l'agent. Schéma retenu : l'agent crée le stack avec les variables non secrètes et l'opérateur ajoute/édite les secrètes dans l'UI avant le 1er déploiement, ou l'opérateur fait l'étape UI ci-dessus de bout en bout.

5. Vérification (post-déploiement)

  1. Portainer → le stack chlova est running ; conteneurs backend, ollama, mcp-portainer, socket-proxy up.
  2. Logs backend : API/UI activée (auth configurée) + healthcheck interne prêt. Pas d'erreur de config fail-closed.
  3. https://chlova.pogoo.app répond (certificat letsencrypt émis) → page de login (mot de passe + TOTP).
  4. Connexion → l'onglet Chat répond ; les outils MCP read-only (n8n/Portainer) sont listés dans l'état (header UI).

6. Rollback

GitOps : revert du commit compose + redeploy, ou Stacks → chlova → Stop/Remove. Le volume chlova-data (SQLite) persiste ; le supprimer pour repartir de zéro.

7. Passage en Phase 2 (plus tard, hors de cette procédure)

Écriture sous gatekeeper + need-review : CHLOVA_PHASE=2 et PORTAINER_READ_ONLY=false (le sidecar autorise alors les mutations, toujours filtrées par le gatekeeper + paliers de risque). À ne faire qu'après validation du cerveau en lecture seule. Voir docs/need-review.md.