5.7 KiB
5.7 KiB
mcp-vps — MCP Linux sur le VPS memory-node (12/07/2026)
Statut : production. Rôle : organe d'action de Claude pendant un blackout NAS
(complète le nœud mémoire — voir common/vps-memory-node.md). Zéro dépendance NAS au runtime.
Accès
- URL publique :
https://mcp.yesminedor.tn/<MCP_PATH_SECRET>/mcp— Cloudflare Tunnel, aucun port ouvert sur l'IP Contabo. Le secret (64 hex) est dans/opt/memory-node/mcp-vps/.env(600) et chez Nabil (Bitwarden/Telegram)./mcpsans secret → 404. - Connecteur claude.ai « vps » : URL complète avec secret, champs OAuth vides (même pattern que mcp-nas : le connecteur ne sait pas envoyer de header Authorization — Cloudflare Access écarté pour cette raison).
- Alerte Telegram à chaque nouvelle session MCP (POST /mcp sans header
mcp-session-id), anti-spam 60 s, non bloquante. Même bot que les alertes SSH claude-oversight. Audit :NEW_SESSION | ip=<CF-Connecting-IP>dans audit.log.
Architecture
- Code :
/opt/memory-node/mcp-vps(git local = source de vérité en blackout ; miroir Giteabolbol/mcp-vps). Dérivé debolbol/linux-mcp-nas(run_command v2, _redact audit, monkey-patch output_schema, fix lifespan — voir runbooks mcp-nas). - Stack compose (2 services, réseau bridge dédié
mcp-vps, aucun port publié) :linux-mcp-vps: build local,init,restart: always,cap_drop: ALL,no-new-privileges, healthcheck GET /health /30s,dns: 1.1.1.1.cloudflared-mcp-vps:tunnel --no-autoupdate run,TUNNEL_TOKENvia.env.
- Volumes :
/opt/memory-node/gitet/opt/memory-node/dataen ro →/mnt/memory-node/{git,data}(miroir bare nas-runbooks + répliques nyora-notes/context-hub ; subdirs seulement : n'expose ni.restic-passni les.envhôte) ;./dataRW (audit.log, root:root 700) ;./ssh-claude→/root/.ssh(clé persistée au recreate). - Outils MCP : run_command, send_keys, capture_pane, list/new/kill/reset_session. PAS d'outils NyoraNotes (service NAS) : lire les répliques via run_command.
- Actions host :
ssh vps.internal '<cmd>'(= claude-oversight@hôte via host-gateway, clé ed25519 dédiéemcp-vps-claude, authorized_keys restreintefrom="172.16.0.0/12", sudoers scopé inchangé — jamais NOPASSWD:ALL). - Firewall : ufw
allow proto tcp from 172.16.0.0/12 to any port 22(containers→host ssh).
Cloudflare (zone + tunnel)
- Zone yesminedor.tn (plan Free) migrée OVH→Cloudflare le 11/07/2026
(NS
kallie/valentin.ns.cloudflare.com). Compte CFf47839fbf54ef0a5ed89db20e9a02902. - Tunnel
mcp-vpsid700c0fe6-2b2c-4e1a-abfa-3f94f2f7c909, config gérée côté Cloudflare (config_src: cloudflare), ingressmcp.yesminedor.tn → http://linux-mcp-vps:8000, fallback 404. DNS : CNAME proxiémcp → <tunnel-id>.cfargotunnel.com(créé au dashboard, le token API n'a pas la permission zone). - Token API CF (
cfat_…, account-owned, chez Nabil) — opérations :
⚠️ un token account-owned (# créer : POST /accounts/<acc>/cfd_tunnel {"name":"…","config_src":"cloudflare"} # ingress : PUT /accounts/<acc>/cfd_tunnel/<id>/configurations # token : GET /accounts/<acc>/cfd_tunnel/<id>/token → TUNNEL_TOKEN .env # état : GET /accounts/<acc>/cfd_tunnel/<id> → status: healthycfat_) se vérifie sur/accounts/<acc>/tokens/verify, PAS/user/tokens/verify(qui renvoie « Invalid API Token »).
Rotations
- Chemin secret :
openssl rand -hex 32→.env→docker compose up -d→ MAJ connecteur claude.ai. - TUNNEL_TOKEN : révocable/regénérable au dashboard Zero Trust ou par API (GET …/token) →
.env→ up. - Clé SSH container : regénérer dans
./ssh-claude(via container éphémère, ownership root), remplacer la ligne dans~claude-oversight/.ssh/authorized_keys(garderfrom="172.16.0.0/12").
Gotchas (coûteux à redécouvrir)
- DNS docker cassé sur ce VPS : le resolv.conf hôte pointe
10.100.0.1(injoignable depuis les bridges docker) → build :network: hostdans compose ; runtime :dns: [1.1.1.1, 8.8.8.8]. cap_drop: ALL⇒ root conteneur SANSCAP_DAC_OVERRIDE: tout volume doit être possédé par root avec modes cohérents (data/700 root,ssh-claude/700 root + clés 600), sinon Permission denied silencieux (audit.log, known_hosts). Créer/chown via container éphémère (docker run --rm -v … chown 0:0 …) — claude-oversight n'a pas le droit de chown vers root.- Miroir bare lu par root conteneur :
chmod -R o+rXsurnas-runbooks.git(700 à la création)git config --system --add safe.directory "*"dans l'image (dubious ownership).
umask 177cassegit add(répertoires objets créés sans bit x → « insufficient permission for adding an object ») : garder umask 022 pour les opérations git ; réparer parfind .git/objects -type d ! -perm -u+x -exec chmod u+rwx {} +.- Jamais de recreate depuis mcp-vps lui-même (suicide) : opérer via Tailscale SSH
(
claude-oversight@100.94.90.119). - Test local du MCP depuis le réseau docker : forcer
-H "Host: mcp.yesminedor.tn"(anti DNS-rebinding du SDK, sinon 421).
Test blackout (validé 12/07/2026)
Via l'URL publique uniquement, zéro appel NAS :
run_command:git -C /mnt/memory-node/git/nas-runbooks.git show main:common/vps-memory-node.md✓run_command:ls /mnt/memory-node/data/{nyora-notes,context-hub}✓run_command:ssh vps.internal 'hostname && id'→ claude-oversight sur l'hôte ✓- Recreate
compose down/up: audit.log + clé SSH persistés, tunnel reconnecte ✓