runbook: mcp-vps (MCP VPS memory-node, Cloudflare Tunnel) — 12/07/2026
This commit is contained in:
parent
af5b268887
commit
8b961332ca
|
|
@ -0,0 +1,87 @@
|
|||
# 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). **`/mcp` sans 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 Gitea `bolbol/mcp-vps`). Dérivé de `bolbol/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_TOKEN` via `.env`.
|
||||
- **Volumes** : `/opt/memory-node/git` et `/opt/memory-node/data` en **ro** →
|
||||
`/mnt/memory-node/{git,data}` (miroir bare nas-runbooks + répliques nyora-notes/context-hub ;
|
||||
subdirs seulement : n'expose ni `.restic-pass` ni les `.env` hôte) ;
|
||||
`./data` RW (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ée `mcp-vps-claude`, authorized_keys restreinte `from="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 CF `f47839fbf54ef0a5ed89db20e9a02902`.
|
||||
- Tunnel **`mcp-vps`** id `700c0fe6-2b2c-4e1a-abfa-3f94f2f7c909`, config gérée côté
|
||||
Cloudflare (`config_src: cloudflare`), ingress `mcp.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 :
|
||||
```
|
||||
# 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: healthy
|
||||
```
|
||||
⚠️ un token **account-owned** (`cfat_`) 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` (garder `from="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: host` dans compose ; runtime : `dns: [1.1.1.1, 8.8.8.8]`.
|
||||
- **`cap_drop: ALL` ⇒ root conteneur SANS `CAP_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+rX` sur `nas-runbooks.git` (700 à la création)
|
||||
+ `git config --system --add safe.directory "*"` dans l'image (dubious ownership).
|
||||
- **`umask 177` casse `git 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 par
|
||||
`find .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 :
|
||||
1. `run_command`: `git -C /mnt/memory-node/git/nas-runbooks.git show main:common/vps-memory-node.md` ✓
|
||||
2. `run_command`: `ls /mnt/memory-node/data/{nyora-notes,context-hub}` ✓
|
||||
3. `run_command`: `ssh vps.internal 'hostname && id'` → claude-oversight sur l'hôte ✓
|
||||
4. Recreate `compose down/up` : audit.log + clé SSH persistés, tunnel reconnecte ✓
|
||||
Loading…
Reference in New Issue