PRISME France 2030 · Culture & IA

Stack LLM marty (edge GPU)

Vérifier la maturitéSpecDoc. générale

Ce dossier déploie la stack GPU sur marty (WRX90, RTX PRO 5000 Blackwell, 48 Go VRAM) :

Internet → Traefik edge marty (:443)
             ├─ marty.nassim.netlib.re → Hermes WebUI :3000
             ├─ hermes.nassim.netlib.re → Hermes dashboard :9119 (+ /v1 → gateway :9000)
             ├─ app.nassim.netlib.re → Hermes Workspace :3002
             └─ *.nassim.netlib.re → home-server via tunnel SSH (:18080)

Docker (réseau interne)
  vLLM :8000 ← alias stable `marty-llm` + id réel du modèle actif
  Hermes WebUI, Hermes Agent, Hermes Dashboard, Hermes Workspace

Contrainte VRAM : un seul gros modèle chargé à la fois (48 Go). La bascule se fait via le registre et le script de switch.

Accès dev sécurisé (poste local → marty)

vLLM écoute uniquement sur 127.0.0.1:8000 du serveur marty (tunnel SSH, pas d'exposition Internet directe).

Port local (poste dev)Cible martyUsage
:19000:9000Hermes gateway (profils + tools)
:18000:8000vLLM OpenAI v1 (alias marty-llm)
systemctl --user enable --now marty-llm-tunnel.service
source ~/.config/opencode/marty-remote.env
opencode -m marty-vllm/marty-llm

Clé API : VLLM_API_KEY dans .env de la stack. Voir marty remote.env.example.

Bascule de modèles

Registre : Configuration (models registry) — dépôts HF, args vLLM, tailles.

IDModèleVRAM ~Notes
hermes-3Hermes-3-Llama-3.1-8B16 GoDéfaut, tool-calling
qwen2.5Qwen2.5-32B-Instruct AWQ19 GoPolyvalent
qwen2.5-72bQwen2.5-72B-Instruct AWQ42 Goctx 8k, serré
qwen3.6-35bQwen3.5-35B-A3B MoE GPTQ-Int425 GoRaisonnement + tools (MoE 3B actifs/token)
qwqQwQ-32B AWQ19 GoRaisonnement (remplace Kimi K2.5)
gemma3Gemma-3-27B-it W4A1618 GovLLM récent requis
deepseek-r1DeepSeek-R1-Distill-Llama-70B AWQ40 Goctx 8k, serré ; Hermes compression override requis
llama3.3Llama-3.3-70B-Instruct AWQ40 Goctx 8k, serré ; Hermes compression override requis

Script (depuis ce poste, via ssh marty-public) :

Stockage local : poids sous <local dir> sur marty. Après pull/pull-all, switch ne recontacte pas HuggingFace.

Accès LAN (LLM_BIND_ADDR=0.0.0.0, UFW actif) :


Hermes et les 34 profils `marty-*` pointent sur l'alias stable `marty-llm` — pas de reconfig Hermes à chaque bascule.

Déploiement complet Hermes + stack :

```bash

Importe automatiquement les profils marty-* depuis marty agents import.manifest. Mot de passe UI : HERMES_WORKSPACE_PASSWORD dans .env sur marty.

Déploiement serveur LLM distant derrière Traefik

Ce dossier prépare aussi la stack GPU d'un serveur LLM distant (historique home-server → marty) :

Traefik home-server (nassim.netlib.re)
  -> IP privée du nouveau serveur
    -> Hermes WebUI :3000
    -> Hermes Agent :9000
    -> vLLM reste interne au réseau Docker

Traefik reste sur home-server. Le nouveau serveur exécute uniquement Docker, vLLM, Hermes WebUI et Hermes Agent.

1. Préparer le nouveau serveur

Installer les prérequis NVIDIA/Docker sur le nouveau serveur :

sudo apt update
sudo apt install -y docker.io docker-compose-plugin nvidia-container-toolkit
sudo systemctl enable --now docker
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

Déployer ce dossier :

mkdir -p ~/deploy
ssh nouveau-serveur
cd ~/deploy/remote-llm-stack
cp .env.example .env
chmod 600 .env

Dans .env, définir au minimum :

Créer les répertoires persistants :

mkdir -p models hermes cache/huggingface

Le modèle attendu par défaut est hermes 3, monté en lecture seule dans vLLM sous hermes 3.

2. Reprendre la configuration locale

Pour reprendre la configuration Hermes locale sans recopier de secrets dans Git :

rsync -a --delete ~/.hermes/ nouveau-serveur:~/deploy/remote-llm-stack/hermes/
ssh nouveau-serveur 'chmod -R go-rwx ~/deploy/remote-llm-stack/hermes'

Si tu préfères repartir proprement, initialise .env depuis le template local :

chmod 600 ~/deploy/remote-llm-stack/hermes/.env

Reporter ensuite les secrets Marty nécessaires : email, calendrier, Baserow, GitLab, Firecrawl, etc.

3. Lancer la stack

Sur le nouveau serveur :

cd ~/deploy/remote-llm-stack
docker compose pull
docker compose up -d
docker compose ps

Tests locaux depuis le nouveau serveur :

curl -fsS http://127.0.0.1:3000/health
curl -fsS http://127.0.0.1:9000/
docker compose exec vllm python3 -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3).read()"
docker compose exec hermes-webui python3 -c "import os, urllib.request; req=urllib.request.Request('http://vllm:8000/v1/models', headers={'Authorization':'Bearer '+os.environ['OPENAI_API_KEY']}); print(urllib.request.urlopen(req, timeout=5).status)"

Tests depuis home-server avec l'IP privée configurée dans .env :

curl -fsS http://IP_PRIVEE_NOUVEAU_SERVEUR:3000/
curl -fsS http://IP_PRIVEE_NOUVEAU_SERVEUR:9000/

4. Brancher Traefik sur home-server

Validation SSH du 2026-05-20 : sur home-server, Traefik tourne en conteneur Docker et expose 80/443. Le conteneur monte un fichier dynamique Configuration (dynamic) plutôt qu'un répertoire dynamique visible.

Ne pas remplacer le fichier dynamique existant sans sauvegarde. Fusionner le contenu de Configuration (dynamic llm stack.example) dans le fichier dynamique existant, ou adapter le montage Traefik pour charger un répertoire dynamique dédié.

Exemple si ton Traefik utilise un répertoire dynamic/file-provider :

sudo cp traefik/dynamic-llm-stack.example.yml /etc/traefik/dynamic/llm-stack.yml
sudo chmod 600 /etc/traefik/dynamic/llm-stack.yml

Exemple si ton Traefik utilise le fichier unique observé Configuration (dynamic) :

sudo cp /etc/traefik/dynamic.yml /etc/traefik/dynamic.yml.bak.$(date +%Y%m%d%H%M%S)
sudoedit /etc/traefik/dynamic.yml

Adapter dans la configuration dynamique :

Générer un hash Basic Auth :

htpasswd -nbB nassim 'mot-de-passe-long'

5. Sécurité réseau

La sécurité repose sur plusieurs couches :

Après activation Traefik, valider que les routes non authentifiées ne passent pas :

curl -I https://marty.nassim.netlib.re # 302 → login WebUI (HERMES_WEBUI_PASSWORD)
curl -I https://hermes.nassim.netlib.re # 200 — pas de Basic Auth Traefik
curl -s https://hermes.nassim.netlib.re/health # 200

Exemple UFW sur le nouveau serveur :

sudo ufw default deny incoming
sudo ufw allow OpenSSH
sudo ufw allow from IP_PRIVEE_HOME_SERVER to any port 3000 proto tcp
sudo ufw allow from IP_PRIVEE_HOME_SERVER to any port 9000 proto tcp
sudo ufw enable

6. URLs prévues

L'API vLLM n'est pas exposée par Traefik. Hermes WebUI et Hermes Agent l'utilisent via http://vllm:8000/v1 sur le réseau Docker interne.