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
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 |
Oui — chlova.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
- Users → Add user :
chlova, mot de passe fort. Non-administrateur. - Environments → vps-pogoo-002 → Access : donner à
chlovale 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 restePORTAINER_READ_ONLY=truecôté sidecar.) - Se connecter en tant que
chlova→ My account → Access tokens → Add token. Copier le token → ce seraPORTAINER_MCP_AUTH_TOKEN.
3b. n8n — projet + membre chlova
- Admin → Users : inviter/créer un utilisateur
chlova. - Projects → New project « CHLOVA » ; ajouter
chlovacomme membre. Y déplacer les workflows que CHLOVA doit voir (les autres restent invisibles). - 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éseauproxy).
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ôtelocal, tandis que CHLOVA et son sidecar tournent survps-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 MCPportainer-pogoo), p. ex.https://<portainer>.pogoo.app. Pas de:9443interne 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)
- Portainer → le stack
chlovaest running ; conteneursbackend,ollama,mcp-portainer,socket-proxyup. - Logs
backend:API/UI activée (auth configurée)+healthcheck interne prêt. Pas d'erreur de config fail-closed. https://chlova.pogoo.apprépond (certificatletsencryptémis) → page de login (mot de passe + TOTP).- 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.