# Hébergement de sites statiques produits par Hermes **Date** : 2026-06-20 **Origine** : Incident panda-dashboard — site hors ligne après redémarrage Container Manager **Applicable** : hermes-tt, hermes-nyora, hermes-perso --- ## LE PROBLÈME À NE JAMAIS REPRODUIRE Hermes-nyora avait servi panda-dashboard via `python3 -m http.server` lancé depuis son propre workspace. Quand Container Manager redémarre, le container Hermes redémarre et le process Python meurt — sans aucune relance automatique. **Un agent Hermes NE DOIT PAS héberger un site en production.** Le workspace d'un agent est éphémère du point de vue de la disponibilité service. --- ## LA RÈGLE > Tout site statique produit par Hermes doit être déployé dans son propre container > Docker dédié avec `restart: always`, via un docker-compose dans `/volume1/docker/`. --- ## PROCÉDURE — Déployer un site statique ### 1. Identifier un port libre Lire `/volume1/docker/ports-registry.md` (accessible depuis l'agent : `/opt/data/workspace/../../../ports-registry.md` — non, passer par l'outil NAS ou demander à Claude). Plages recommandées : 3040-3099, 8800-8899. ### 2. Créer le docker-compose dans /volume1/docker/ L'agent écrit le fichier dans son workspace, puis demande au MCP NAS de le déplacer. Ou bien Claude le crée directement via mcp-nas. **Template à copier :** ```yaml # — description courte # Port : services: : image: nginx:alpine container_name: restart: always ports: - ":80" volumes: - /volume1/docker/hermes-platform/hermes-/data/workspace/:/usr/share/nginx/html:ro networks: - n8n_default networks: n8n_default: external: true ``` ### 3. Déployer via API Portainer Portainer est accessible sur `http://172.17.0.1:9000` depuis les containers Docker. ```bash # Obtenir JWT JWT=$(curl -s -X POST http://172.17.0.1:9000/api/auth \ -H "Content-Type: application/json" \ -d '{"username":"bestof","password":"2L2u519wportainer"}' \ | grep -o '"jwt":"[^"]*"' | cut -d'"' -f4) # Créer le stack (endpointId=2 = local) curl -s -X POST "http://172.17.0.1:9000/api/stacks/create/standalone/string?endpointId=2" \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d "{ \"name\": \"\", \"stackFileContent\": $(cat /chemin/vers/docker-compose.yml | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'), \"env\": [] }" ``` **Vérification :** ```bash JWT= curl -s "http://172.17.0.1:9000/api/endpoints/2/docker/containers/json?filters=%7B%22label%22%3A%5B%22com.docker.compose.project%3D%22%5D%7D" \ -H "Authorization: Bearer $JWT" | python3 -c " import json,sys for c in json.load(sys.stdin): print(c['Names'], c['State'], c['Status']) " ``` ### 4. Configurer le Reverse Proxy DSM DSM → Panneau de configuration → Portail d'applications → Proxy inversé : - Source : HTTPS, `.bolbol.tn`, port 443 - Destination : HTTP, `192.168.100.33`, port `` ### 5. Mettre à jour ports-registry.md ```bash # Ajouter la ligne dans le tableau Services Actifs # Marquer le port comme OCCUPE dans Plages libres # Ajouter une ligne dans Historique des modifications ``` ### 6. Commit Gitea ```bash cd /volume1/docker/ git init git add . git commit -m "deploy: nginx statique port " git push http://bolbol:2L2u519wgitea@192.168.100.33:3232/bolbol/nas-runbooks.git ``` --- ## EXEMPLE CONCRET — panda-dashboard (2026-06-20) - **Dossier source** : `/volume1/docker/hermes-platform/hermes-nyora/data/workspace/panda-dashboard/` - **Port** : 3021 - **Domaine** : panda.bolbol.tn - **Stack Portainer** : ID 314 - **Compose** : `/volume1/docker/panda-dashboard/docker-compose.yml` --- ## RAPPEL SÉCURITÉ - Ne jamais stocker de données sensibles dans le workspace monté en lecture publique - Le volume est monté `:ro` (read-only) — le container nginx ne peut pas modifier les fichiers - Le mot de passe Portainer est dans `/volume1/docker/hermes-platform/.env`