Installer Hermes Agent sur un VPS avec Docker : le guide complet
Comment j'ai installé Hermes Agent (l'OpenClaw Killer) sur un VPS : connexion SSH, OAuth, configuration DNS, reverse proxy HTTPS et les pièges réels de prod.
Comment j'ai installé Hermes Agent (l'OpenClaw Killer) sur un VPS : connexion SSH, OAuth, configuration DNS, reverse proxy HTTPS et les pièges réels de prod.
Qu'est-ce qu'un agent IA autonome ? C'est un programme à qui tu donnes un objectif, pas une suite d'instructions. Il décide lui-même des étapes, utilise des outils (web, fichiers, terminal, code) et avance seul jusqu'au résultat. Là où un chatbot répond, un agent agit.
Hermes, c'est exactement ça sauf que tu peux le faire tourner sur ta propre machine, que tu contrôles de bout en bout. Et c'est là que ça se corse : connexion SSH, authentification qui expire toutes les heures, DNS, permissions de fichiers... autant d'embûches que les tutoriels passent sous silence.
Dans ce guide, je te montre comment j'ai déployé Hermes Agent (de Nous Research) sur un VPS Ubuntu avec Docker, de la première connexion SSH jusqu'à l'agent qui répond dans une interface de chat accessible via ton nom de domaine. Tu vas apprendre à te connecter au serveur, à conteneuriser Hermes, à le brancher sur un fournisseur d'inférence via OAuth, à configurer tes DNS et à l'exposer derrière un reverse proxy HTTPS.
C'est un retour d'expérience terrain, pas une doc théorique. Chaque piège que je décris, je l'ai rencontré et résolu pour de vrai.
Hermes Agent, c'est un agent IA autonome et open source développé par Nous Research, qui apprend, mémorise et s'améliore automatiquement de session à session. Là où un chatbot classique se contente de répondre, Hermes peut chercher sur le web, lire et écrire des fichiers, exécuter du code dans un terminal, générer des images, et bien plus.
Imagine la différence entre un collègue qui te donne des conseils par téléphone et un collègue qui s'assoit à ton poste et fait le travail. Le premier, c'est un LLM brut. Le second, c'est un agent.
Concrètement, Hermes se branche sur un fournisseur d'inférence (ici Nous Portal, qui donne accès à plus de 300 modèles comme Claude Sonnet, GPT, etc.) et y ajoute toute une couche d'outils orchestrés. Le projet est développé par Nous Research, et sa documentation officielle se trouve sur hermes-agent.nousresearch.com.

L'autre grand nom du créneau, c'est OpenClaw (ex-Moltbot) : un agent open source qui vit dans tes messageries (WhatsApp, Telegram, Slack…), avec un système de skills communautaires et un heartbeat qui le fait agir tout seul.
J'ai choisi Hermes pour trois raisons :
Intégration : Hermes expose une API compatible OpenAI, donc il se branche sur ma stack (Open WebUI, scripts). OpenClaw, lui, est taillé pour la messagerie.
Intelligence différente : Il utilise beaucoup Python (plutôt que Node.js), ce qui lui donne une couche d'intelligence différente et parfois plus adaptée.
*Auto-amélioration via les skills : Hermes peut créer, modifier et apprendre de nouveaux "skills" au fil de l'utilisation (Gmail, Telegram, etc.). Il comprend et modifie même son propre code.
*Système de mémoire structuré : Il possède des fichiers memory.md et user.md avec une gestion de contexte propre (context files, @références), ce qui lui permet de mieux se souvenir des préférences et habitudes de l'utilisateur.

Faire tourner Hermes en local sur ta machine, c'est bien pour tester. Mais pour un usage sérieux, tu veux qu'il tourne en permanence, qu'il survive aux redémarrages, et qu'il soit accessible de partout. C'est exactement le rôle d'un VPS + Docker.
Voici les bénéfices concrets de cette approche :
Avant de toucher à Docker, il faut accéder à ton serveur. La connexion se fait en SSH (Secure Shell), le protocole standard pour piloter une machine distante en ligne de commande.
Ton hébergeur t'a fourni trois informations : l'adresse IP du VPS, un nom d'utilisateur (souvent ubuntu ou root), et soit un mot de passe, soit une clé SSH. Je te recommande fortement la clé SSH, bien plus sûre qu'un mot de passe.
Pour te connecter avec une clé privée :
ssh -i /chemin/vers/ta_cle_privee ubuntu@ton.adresse.ipSur Windows, le chemin ressemble à C:\Users\TonNom\.ssh\private_key. Sur Mac ou Linux, plutôt ~/.ssh/id_rsa.
Si c'est ta première connexion, SSH te demande de confirmer l'empreinte du serveur, tape yes. Une fois connecté, ton prompt change pour afficher le hostname du serveur, par exemple :
ubuntu@mon-vps:~$Le $ à la fin du prompt indique que tu es un utilisateur normal. Un # indiquerait que tu es root. Travaille autant que possible en utilisateur normal (ubuntu) et n'utilise sudo que quand c'est nécessaire.
Vérifie que Docker est bien installé sur le VPS :
docker --version
docker compose versionSi Docker n'est pas là, installe-le via le script officiel :
curl -fsSL https://get.docker.com | shMaintenant que tu es connecté et que Docker tourne, on peut construire notre image.
L'idée est de partir d'une image Python légère et d'installer Hermes via pipx (qui isole l'outil dans son propre environnement). On ajoute aussi le binaire Docker statique, indispensable si tu veux que ton agent puisse créer des conteneurs sandbox plus tard.
Voici le Dockerfile que j'utilise :
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
curl nodejs npm && \
rm -rf /var/lib/apt/lists/*
# CLI docker (binaire statique) pour le backend terminal sandboxé
RUN curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz \
| tar -xz -C /usr/local/bin --strip-components=1 docker/docker
RUN pip install --no-cache-dir pipx && \
pipx install hermes-agent && \
pipx inject hermes-agent aiohttp fastapi uvicorn ptyprocess "mcp>=1.27" httpx-sse langfuse && \
ln -s /root/.local/bin/hermes /usr/local/bin/hermes
WORKDIR /root
COPY start.sh /start.sh
RUN chmod +x /start.sh
EXPOSE 8642 9119
CMD ["/start.sh"]Quelques points clés sur ce fichier :
Le CMD du Dockerfile pointe vers un start.sh. Ce script lance le dashboard en arrière-plan, puis la gateway (le serveur API) au premier plan :
#!/bin/sh
umask 0000
# Dashboard en arrière-plan
hermes dashboard --host 0.0.0.0 --port 9119 --no-open --insecure --skip-build &
# Gateway au premier plan (inclut le serveur API)
exec hermes gatewayLe umask 0000 mérite une explication. Par défaut, Hermes (qui tourne en root dans le conteneur) crée ses fichiers en 0600, donc lisibles uniquement par root. Si tu partages un dossier avec d'autres outils, ils ne pourront pas lire ces fichiers. Le umask 0000 force la création en mode permissif.
Ca t'évitera des heures de debug sur des "Permission denied" mystérieux.
On assemble tout dans un docker-compose.yml. Ici, je connecte Hermes à un réseau Docker existant (celui où tournent mes autres services) et je monte le volume de la config Hermes.
services:
hermes-api:
build: .
container_name: hermes-api
restart: unless-stopped
expose:
- "8642"
- "9119"
volumes:
- ./auth:/root/.hermes
networks:
- n8nnet
networks:
n8nnet:
external: true
name: mon-reseau-dockerLe montage ./auth:/root/.hermes est crucial : il fait persister la configuration et l'authentification de Hermes hors du conteneur. Sans ça, à chaque redémarrage tu perdrais ta connexion au fournisseur d'inférence.
Règle à retenir : une modification du docker-compose.yml (ajout d'un volume, d'un port) nécessite de recréer le conteneur avec docker compose up -d --force-recreate. Un simple restart ne suffit pas à appliquer un nouveau volume.
C'est là que ça devient intéressant. Hermes a besoin d'un cerveau, c'est-à-dire d'un modèle d'inférence. Dans mon cas, je passe par Nous Portal en OAuth.
Lance la commande d'authentification dans le conteneur :
docker exec -it hermes-api hermes auth add nous --type oauth --no-browser
Le flag --no-browser est indispensable sur un serveur headless : il te donne une URL à ouvrir sur ta propre machine, tu t'authentifies, puis tu colles le code de retour.
Une fois connecté, sélectionne ton modèle par défaut :
docker exec -it hermes-api hermes model
Vérifie que tout est en place :
docker exec hermes-api hermes portal infoTu dois voir ✓ logged in et la liste des outils disponibles (web search, image generation, etc.).

Quand tu te connectes en OAuth, Hermes stocke tes identifiants dans un fichier auth.json, à l'intérieur de /root/.hermes/. Ce fichier contient deux choses importantes : un access token (le jeton qui sert à appeler l'API) et un refresh token (le jeton qui sert à régénérer l'access token quand il expire).
L'access token OAuth a une durée de vie courte, quelques heures en général. Passé ce délai, il devient invalide. Pour ne pas avoir à te reconnecter manuellement toutes les heures, Hermes utilise le refresh token pour réécrire automatiquement un nouveau access token dans auth.json. C'est ce mécanisme de refresh qui permet à ton agent de tourner en continu sans intervention.
Premier vrai obstacle que j'ai rencontré : après quelques heures, l'agent tombait en erreur d'authentification, et le refresh automatique échouait avec un message du type "Device or resource busy".
La cause était subtile. Dans mon premier compose, j'avais monté le fichier auth.json seul comme volume Docker, façon ./auth.json:/root/.hermes/auth.json. Le problème : quand Docker monte un fichier individuel, il le verrouille en place. Or le mécanisme de refresh de Hermes ne se contente pas de modifier le contenu du fichier, il fait une réécriture atomique (il écrit un fichier temporaire puis remplace l'ancien par un rename). Et tu ne peux pas remplacer un fichier que Docker a monté individuellement. D'où le "Device busy", et le refresh qui échoue en boucle.
La solution est de monter le dossier parent complet, pas le fichier :
volumes:
- ./auth:/root/.hermes # ✅ le dossier entier
# PAS ./auth/auth.json:/root/.hermes/auth.json ❌ le fichier seulEn montant le dossier /root/.hermes en entier, Hermes peut créer son fichier temporaire et faire le rename à l'intérieur du dossier monté, sans conflit avec Docker. Le refresh fonctionne alors parfaitement, et ton token se régénère tout seul indéfiniment.
Règle à retenir : avec Docker, monte toujours le dossier de config, jamais un fichier de config isolé qui doit être réécrit par l'application. C'est valable pour Hermes, mais aussi pour plein d'autres outils qui font de la réécriture atomique.
Si tu t'es déjà retrouvé dans l'état cassé (fichier monté seul), corrige le compose puis force une reconnexion propre :
docker exec -it hermes-api hermes auth add nous --type oauth --no-browserLe nouveau login réécrit un auth.json valide dans le dossier correctement monté.
Ton agent tourne, mais il n'est accessible que depuis l'intérieur du réseau Docker. Pour y accéder via un nom de domaine avec HTTPS, deux choses à mettre en place : faire pointer ton domaine vers ton VPS (les DNS), puis router le trafic vers le bon conteneur (le reverse proxy).
Avant qu'un nom comme dash.mondomaine.com mène à ton serveur, il faut créer un enregistrement DNS qui associe ce nom à l'adresse IP de ton VPS. C'est ce qui permet au navigateur de savoir où aller quand quelqu'un tape ton domaine.
Rends-toi dans l'interface de gestion DNS de ton registrar (l'endroit où tu as acheté ton domaine, type OVH, Cloudflare, Namecheap, Infomaniak) et crée un enregistrement de type A :
| Type | Nom (sous-domaine) | Valeur (cible) |
|---|---|---|
| A | dash | ton.adresse.ip.vps |
| A | chat | ton.adresse.ip.vps |
Le type A associe un nom à une adresse IPv4. Le "Nom" est le sous-domaine que tu veux (dash donnera dash.mondomaine.com), et la "Valeur" est l'IP de ton VPS, la même que celle que tu utilises pour te connecter en SSH.
Si tu veux exposer plusieurs services (dashboard, interface de chat, etc.), crée un enregistrement A par sous-domaine. Astuce alternative : un enregistrement wildcard * qui fait pointer tous les sous-domaines vers ton IP d'un coup, pratique si tu prévois d'en ajouter beaucoup.
Attention : la propagation DNS n'est pas instantanée. Compte de quelques minutes à quelques heures selon ton registrar.
Tu peux vérifier que ton enregistrement est actif avec la commande dig depuis ton VPS :
dig +short dash.mondomaine.comSi ça renvoie l'IP de ton VPS, le DNS est propagé et tu peux passer à la suite. Si ça ne renvoie rien, patiente, l'enregistrement n'est pas encore propagé.
Une fois les DNS en place, j'utilise Caddy comme reverse proxy. Son gros avantage : il obtient et renouvelle automatiquement les certificats HTTPS Let's Encrypt, sans configuration manuelle. Dès que ton DNS pointe correctement, Caddy détecte le domaine et génère le certificat tout seul.
Voici un bloc Caddy type pour exposer le dashboard, protégé par une authentification basique :
dash.mondomaine.com {
basic_auth {
admin <hash_bcrypt_du_mot_de_passe>
}
reverse_proxy hermes-api:9119
}Pour générer le hash bcrypt de ton mot de passe :
docker exec caddy caddy hash-password --plaintext "ton-mot-de-passe"Après avoir modifié le Caddyfile, recharge la config sans couper le service :
docker exec caddy caddy reload --config /etc/caddy/CaddyfileSi tu exposes une interface qui utilise des WebSockets (comme une instance Obsidian web ou certaines UI temps réel), le simple reverse_proxy peut ne pas suffire. Ajoute les en-têtes qui préservent l'origine :
obsidian.mondomaine.com {
basic_auth {
admin <hash_bcrypt>
}
reverse_proxy obsidian:3000 {
header_up Host {host}
header_up X-Real-IP {remote_host}
}
}J'ai galéré sur ce point : la page se chargeait à moitié puis affichait "Erreur de chargement". Le certificat HTTPS était bien obtenu, le conteneur répondait, mais le handshake WebSocket échouait. Les header_up ont réglé le problème.
Pour discuter avec ton agent dans un vrai chat (plutôt qu'en ligne de commande), Open WebUI est parfait. Il consomme l'API compatible OpenAI que Hermes expose.
Dans Open WebUI, va dans Admin Settings → Connections → Add Connection et renseigne :
| Champ | Valeur |
|---|---|
| URL | http://hermes-api:8642/v1 |
| Key | Ta clé API Hermes (dans /root/.hermes/.env) |

Ton agent apparaît alors dans le menu déroulant des modèles. Sélectionne-le, et tu peux lui parler. La différence avec un modèle brut ? Quand tu lui demandes de lire un fichier ou de chercher sur le web, il utilise réellement ses outils.

Attention : ne confonds pas l'agent (qui a les outils) avec un modèle brut connecté en parallèle. Si tu sélectionnes un modèle brut dans le menu, il te répondra "je n'ai pas accès aux fichiers". Vérifie toujours que c'est bien ton agent Hermes qui est sélectionné.
Voici les obstacles que j'ai croisés en production, avec leur solution. C'est la partie que les tutoriels oublient toujours.
Docker stocke ses images et conteneurs dans /var/lib/docker, sur le disque système. Si ton VPS a un petit disque système (le mien faisait moins de 20 Go), tu satures vite, surtout quand Hermes crée des conteneurs sandbox.
La solution : déplacer le stockage Docker sur ton volume de données. Crée ou édite /etc/docker/daemon.json :
{
"data-root": "/mnt/data/docker"
}Pour containerd, ajuste aussi /etc/containerd/config.toml pour pointer root vers /mnt/data/containerd. Après un redémarrage du démon, ton disque système respire.
Hermes tourne en root, mais d'autres outils (Obsidian, ton utilisateur SSH) tournent souvent en UID 1000. Quand Hermes écrit dans un dossier partagé, les fichiers appartiennent à root et sont illisibles par les autres.
Le correctif rapide :
sudo chmod -R 777 ~/hermes-proxy/vault
sudo chown -R 1000:1000 ~/hermes-proxy/vaultLe correctif permanent, c'est le umask 0000 dans le start.sh qu'on a vu plus haut. Il fait que les nouveaux fichiers sont créés en mode lisible par tous dès le départ.
Petit rappel qui m'a fait perdre du temps : si tu as installé Hermes uniquement dans le conteneur (pour économiser de l'espace), la commande hermes n'existe pas sur l'hôte. Tu obtiens un command not found. Toute commande doit passer par :
docker exec -it hermes-api hermes [commande]
Voici les étapes essentielles pour déployer Hermes sur ton VPS :
| Étape | Commande clé |
|---|---|
| Se connecter au VPS | ssh -i cle_privee ubuntu@ton.ip |
| Construire l'image | docker compose up -d --build |
| Authentifier le fournisseur | hermes auth add nous --type oauth --no-browser |
| Choisir le modèle | hermes model |
| Vérifier l'état | hermes portal info |
| Vérifier un DNS | dig +short dash.mondomaine.com |
| Recréer après modif compose | docker compose up -d --force-recreate |
Et les pièges à garder en tête :
Tu as maintenant un agent IA autonome qui tourne sur ton propre serveur, accessible en SSH pour l'admin et via une interface de chat sur ton domaine, avec accès à des outils. C'est la fondation solide.
Mais un seul agent, aussi capable soit-il, reste limité : il fait tout lui-même, en série. La vraie montée en puissance, c'est quand tu passes d'un agent unique à une organisation d'agents qui collaborent. Imagine un orchestrateur qui reçoit un objectif, le découpe en tâches, et les distribue à des dizaines de spécialistes (un agent recherche, un agent rédaction, un agent qui vérifie le travail des autres), le tout coordonné par un tableau kanban partagé.
C'est exactement ce que je te montre dans le prochain article : comment construire une armée de 48 agents IA sur Hermes, avec un système d'orchestration, de délégation via kanban, et des tâches planifiées en autonomie par cron. Tu y découvriras le système de profils, le rôle du fichier SOUL.md, et les pièges costauds que j'ai dû résoudre (la limite du superviseur s6, les conflits de bot, l'environnement qui casse la délégation).
Si ce guide t'a permis de poser la fondation, le prochain te montre comment bâtir l'immeuble dessus.