Files
nas-runbooks/common/hermes-hub-deploiement.md
T

84 lines
4.2 KiB
Markdown

# Hermes Hub — Déploiement et Exploitation Multi-Univers sur VPS
**Instance auteur** : gemini / nabil
**Date** : 2026-08-20
**Tags** : hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi, subdomains, filebrowser, dsh, basic-auth, secret-hardening
**Statut** : valide (testé et vérifié en direct sur VPS Contabo avec secret cryptographique aléatoire)
---
## Problème
Nabil dispose de 4 instances Hermes strictement cloisonnées :
- **TT** (`hermes-tt`, port 3010, NAS Synology) — Achats Zone Sud, Tunisie Telecom
- **Nyora** (`hermes-nyora`, port 3020, NAS Synology) — Venture perso, Dr Nexum
- **Perso** (`hermes-perso`, port 3031, NAS Synology) — Famille, personnel, santé
- **Nabil** (`hermes-nabil`, port 9119, VPS Contabo) — Master agent & DeepSeek Harness (DSH)
L'objectif est d'offrir une interface web unifiée sur le VPS Contabo (`100.94.90.119`) avec :
1. Un **Workspace Switcher** latéral fluide et étanche entre les 4 univers.
2. Un **Sélecteur Toggle DSH** (conception Claude Design) pour basculer instantanément entre la session et l'explorateur de fichiers DSH (`https://dsh.hub.yesminedor.tn/`).
3. L'absence totale de fuite de contexte, de mémoire JS ou de cookies de session entre univers.
4. La résolution 100% native des assets absolus (`/assets/main-*.js`) via un routage par **sous-domaine dédié** (`*.hub.yesminedor.tn`).
5. La sécurisation intégrale via **Cloudflare Access** (OTP Email + 2FA) et **Basic Auth** scrypt avec secret de session cryptographique aléatoire 32 bytes (HMAC-SHA256).
---
## Architecture & Configuration
### 1. Routage par Sous-Domaine
- `hub.yesminedor.tn` : Shell du Workspace Switcher (UI d'orchestration)
- `tt.hub.yesminedor.tn` : Proxy direct vers Hermes TT (`http://100.86.197.88:3010`)
- `nyora.hub.yesminedor.tn` : Proxy direct vers Hermes Nyora (`http://100.86.197.88:3020`)
- `perso.hub.yesminedor.tn` : Proxy direct vers Hermes Perso (`http://100.86.197.88:3031`)
- `nabil.hub.yesminedor.tn` : Proxy direct vers Hermes Nabil (`http://hermes-nabil:9119`)
- `dsh.hub.yesminedor.tn` : Proxy direct vers Filebrowser DSH (`http://dsh-vps-filebrowser:8080`)
### 2. Configuration Basic Auth `hermes-nabil`
Fichier : `/data/config.yaml` dans le conteneur `hermes-nabil` :
```yaml
dashboard:
basic_auth:
username: nabil
password_hash: "scrypt+h8nCk5/CqFiypw==/3i04g/Fc50AiN2bpDEyju3MjfStkYvFdUPrs="
secret: "<secret aléatoire 32 bytes hex - HMAC-SHA256>"
```
- **Username** : `nabil`
- **Mot de passe** : `NabilMasterHermes2026!`
- **Secret de session** : généré aléatoirement (64 caractères hexadécimaux).
---
## Preuves Directes de Fonctionnement
### Preuve 1 : Routage Sous-Domaines & Assets JS
```
PROVEN OK [HTTP 200] | Host: hub.yesminedor.tn | Main Hub Switcher UI | text/html; charset=utf-8 | 9385 bytes
PROVEN OK [HTTP 200] | Host: tt.hub.yesminedor.tn | Universe TT Root HTML | text/html; charset=utf-8 | 11026 bytes
PROVEN OK [HTTP 200] | Host: tt.hub.yesminedor.tn | Universe TT Main JS Bundle | application/javascript | 2039429 bytes
PROVEN OK [HTTP 200] | Host: nyora.hub.yesminedor.tn | Universe Nyora Root HTML | text/html; charset=utf-8 | 11026 bytes
PROVEN OK [HTTP 200] | Host: perso.hub.yesminedor.tn | Universe Perso Root HTML | text/html; charset=utf-8 | 11026 bytes
PROVEN OK [HTTP 200] | Host: nabil.hub.yesminedor.tn | Universe Nabil Root HTML | text/html; charset=utf-8 | 10045 bytes
PROVEN OK [HTTP 200] | Host: dsh.hub.yesminedor.tn | DSH Filebrowser Root HTML | text/html; charset=utf-8 | 6112 bytes
```
### Preuve 2 : Cycle d'authentification complet
```
=== 1. LOGIN STATUS ===
HTTP Status: 200
Session Info: {'ok': True, 'next': '/'}
=== 2. SET-COOKIE HEADERS RECEIVED ===
-> hermes_session_at=... (Max-Age=43200; Path=/; SameSite=lax)
-> hermes_session_rt=... (Max-Age=2592000; Path=/; SameSite=lax)
-> hermes_session_provider=basic (Max-Age=2592000; Path=/; SameSite=lax)
=== 3. REQUESTING AUTHENTICATED DASHBOARD / ===
Authenticated Home Status: 200
HTML Title Tag: ['<title>Hermes Agent - Dashboard</title>']
=== 4. REQUESTING AUTHENTICATED API /api/sessions ===
API Sessions Status: 200
API Sessions Response Keys: ['sessions', 'total', 'limit', 'offset']
```