Aller au contenu principal

Installer Hermes Agent (agent IA) sur un VPS

Ce guide vous explique comment installer Hermes Agent sur un VPS HostMyServers. Hermes est un framework d'agent IA open source (licence MIT) édité par Nous Research. Contrairement à un assistant de code utilisé en direct sur votre poste (Claude Code, OpenCode…), Hermes tourne en permanence sur un serveur : vous lui parlez depuis votre messagerie (Discord, Telegram, Slack…), il travaille de manière autonome en arrière-plan, garde une mémoire de vos échanges, apprend de nouvelles procédures (skills) et peut exécuter des tâches planifiées.

Le déploiement s'appuie sur Docker Compose avec une configuration durcie, et l'interface web d'administration n'est accessible que via un VPN (Tailscale), jamais depuis Internet.

Source

Ce guide s'inspire du retour d'expérience de l'article « Hermes : simple hype ou vraie révolution ? » (damyr.fr) et de la documentation officielle Hermes Agent.

Commander un serveur

Hermes ne fait pas tourner de modèle d'IA en local : il appelle des modèles distants (OpenRouter, Anthropic, Nous Portal…). Un petit VPS suffit donc largement :

Prérequis

  • Accès SSH root ou utilisateur avec sudo
  • Système Ubuntu 24.04 LTS ou Debian 12/13
  • Un compte chez un fournisseur de modèles (par exemple OpenRouter) avec une clé API
  • Un compte Tailscale (gratuit pour un usage personnel) pour accéder à l'interface web
  • Un compte Discord (ou Telegram, Slack…) pour discuter avec l'agent

Configuration requise

ComposantMinimumRecommandé
RAM2 Go4 Go
CPU1 vCPU2 vCPU
Stockage10 Go20 Go
Mémoire

L'auteur de l'article fait tourner Hermes sur un VPS 2 vCPU / 2 Go, mais recommande au moins 4 Go de RAM dès que vous utilisez l'automatisation de navigateur (Playwright/Chromium) ou plusieurs sous-agents.

Connectez-vous en SSH, pas via la console web

Les consoles navigateur (noVNC) transmettent mal certains caractères (:, @, =) et peuvent corrompre silencieusement les commandes et clés API collées. Utilisez une vraie session SSH.

Connexion et mise à jour du système

ssh utilisateur@adresse_ip_serveur
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg openssl

Installation de Docker

L'image Docker officielle est la méthode d'installation recommandée par Hermes : l'image est sans état, toutes les données vivent dans un seul dossier monté (/opt/data), et une mise à jour se résume à tirer une nouvelle image.

Installez Docker Engine et le plugin Compose depuis le dépôt officiel Docker :

sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
curl -fsSL https://download.docker.com/linux/$ID/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$ID $VERSION_CODENAME stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

Vérifiez l'installation :

docker --version
docker compose version

Installation de Tailscale (accès privé)

L'interface web d'Hermes permet de tout administrer (clés API, configuration, MCP, plugins, exécution de commandes via l'agent). Elle ne doit jamais être exposée sur Internet : des instances ouvertes sur 0.0.0.0 ont été compromises par des scanners automatiques (installation de clés SSH malveillantes via l'agent). On la rend donc accessible uniquement depuis votre réseau privé Tailscale.

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Ouvrez le lien d'authentification affiché pour rattacher le serveur à votre compte Tailscale, puis récupérez l'adresse IP Tailscale du VPS (plage 100.x.y.z) :

tailscale ip -4

Notez cette adresse : elle servira d'adresse d'écoute pour l'interface web. Installez aussi Tailscale sur votre ordinateur ou votre téléphone pour pouvoir y accéder.

Pourquoi lier le port à l'IP Tailscale ?

Docker écrit ses propres règles iptables et contourne le pare-feu UFW pour les ports publiés. Publier le port sur l'adresse Tailscale (et non sur 0.0.0.0) garantit qu'il n'est pas joignable depuis l'interface publique, quel que soit l'état du pare-feu.

Préparation des répertoires

sudo mkdir -p /opt/hermes/data
sudo chown -R 10000:10000 /opt/hermes/data
sudo chmod 0750 /opt/hermes/data
cd /opt/hermes

Le conteneur exécute l'agent avec l'utilisateur non privilégié UID/GID 10000 : le dossier de données doit lui appartenir.

Fichier d'environnement

Créez le fichier /opt/hermes/.env qui contiendra l'adresse d'écoute et les identifiants de l'interface web :

sudo nano /opt/hermes/.env
# Adresse Tailscale du serveur (résultat de `tailscale ip -4`) — JAMAIS 0.0.0.0
HERMES_BIND_ADDR=100.x.y.z
HERMES_DASHBOARD_PORT=9119

# Identifiants de l'interface web
HERMES_DASHBOARD_BASIC_AUTH_USERNAME=admin
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=MOT_DE_PASSE
HERMES_DASHBOARD_BASIC_AUTH_SECRET=SECRET

# Limites de ressources (adaptez à votre VPS : ~1200m pour 2 Go, 3g pour 4 Go)
HERMES_MEMORY_LIMIT=1200m
HERMES_CPU_LIMIT=1.5

TZ=Europe/Paris

Générez le mot de passe et le secret de session, puis reportez-les dans le fichier :

openssl rand -base64 24 # -> HERMES_DASHBOARD_BASIC_AUTH_PASSWORD
openssl rand -hex 32 # -> HERMES_DASHBOARD_BASIC_AUTH_SECRET
Secret d'au moins 16 octets

HERMES_DASHBOARD_BASIC_AUTH_SECRET doit faire au moins 16 octets. En dessous, le module d'authentification ne s'active pas et l'interface refuse de démarrer avec l'erreur trompeuse « no auth providers are registered ». openssl rand -hex 32 est largement suffisant. Gardez ce secret stable : le changer invalide les sessions ouvertes.

Protégez le fichier, il contient des secrets :

sudo chmod 0600 /opt/hermes/.env

Configuration Docker Compose

Créez /opt/hermes/compose.yaml :

sudo nano /opt/hermes/compose.yaml
services:
hermes:
image: nousresearch/hermes-agent:latest
container_name: hermes
command: gateway run
restart: unless-stopped
stop_grace_period: 30s

# Aucun processus du conteneur ne peut acquérir de nouveaux privilèges
security_opt:
- no-new-privileges:true
# Retire toutes les capacités Linux par défaut...
cap_drop:
- ALL
# ...et ne rend que celles nécessaires à l'initialisation du conteneur
cap_add:
- CHOWN
- FOWNER
- DAC_OVERRIDE
- SETUID
- SETGID
- KILL
# Évite les erreurs liées à un trop grand nombre de fichiers ouverts
ulimits:
nofile:
soft: 4096
hard: 8192

ports:
# Interface web publiée UNIQUEMENT sur l'adresse Tailscale
- "${HERMES_BIND_ADDR}:${HERMES_DASHBOARD_PORT:-9119}:${HERMES_DASHBOARD_PORT:-9119}"

volumes:
# Toutes les données de l'agent : config, clés, mémoire, skills, crons, logs
- ./data:/opt/data
# Ne montez JAMAIS /var/run/docker.sock : cela donnerait l'équivalent root sur l'hôte

environment:
PUID: "10000"
PGID: "10000"
TZ: "${TZ:-Europe/Paris}"
# Interface web (supervisée dans le même conteneur que la gateway)
HERMES_DASHBOARD: "1"
HERMES_DASHBOARD_HOST: "0.0.0.0" # dans le conteneur uniquement ; côté hôte, seul Tailscale est exposé
HERMES_DASHBOARD_PORT: "${HERMES_DASHBOARD_PORT:-9119}"
HERMES_DASHBOARD_BASIC_AUTH_USERNAME: "${HERMES_DASHBOARD_BASIC_AUTH_USERNAME}"
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD: "${HERMES_DASHBOARD_BASIC_AUTH_PASSWORD}"
HERMES_DASHBOARD_BASIC_AUTH_SECRET: "${HERMES_DASHBOARD_BASIC_AUTH_SECRET}"
# Garde-fous de l'agent
HERMES_WRITE_SAFE_ROOT: "/opt/data" # l'agent ne peut écrire que dans son dossier de données
HERMES_YOLO_MODE: "0" # les commandes dangereuses restent soumises à approbation

shm_size: "256m"

deploy:
resources:
limits:
memory: "${HERMES_MEMORY_LIMIT:-1200m}"
cpus: "${HERMES_CPU_LIMIT:-1.5}"
pids: 512

# Évite qu'un agent très bavard ne remplisse le disque
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Image durcie de la communauté

L'auteur de l'article publie une variante de l'image officielle (DamyrFr/hermes-docker) qui ajoute notamment rtk (filtrage des sorties de commandes pour réduire la consommation de tokens) et supprime les binaires setuid. La configuration ci-dessus en reprend les réglages de sécurité avec l'image officielle.

Premier lancement : l'assistant de configuration

Avant de démarrer le service, lancez une fois l'assistant interactif (interface en mode texte). Il vous demande votre fournisseur de modèles, vos clés API, et vous propose de configurer la messagerie (gateway) :

cd /opt/hermes
sudo docker compose run --rm hermes setup

Pendant l'assistant :

  1. Fournisseur de modèles : choisissez par exemple OpenRouter et collez votre clé API. Alternative : hermes setup --portal avec un abonnement Nous Portal (300+ modèles et outils web inclus, sans clés à gérer).
  2. Outils : activez la recherche web et l'extraction de pages (voir plus bas).
  3. Messagerie : configurez Discord (voir section suivante) — c'est la principale interface avec l'agent.
  4. Les paramètres obscurs peuvent être laissés par défaut, tout est modifiable ensuite.

Les clés sont enregistrées dans /opt/hermes/data/.env et la configuration dans /opt/hermes/data/config.yaml.

Budget maîtrisé avec OpenRouter

OpenRouter permet de fixer une limite de dépense par clé API, réinitialisable périodiquement. C'est idéal pour une instance personnelle facturée à la consommation.

Créer le bot Discord (gateway)

La gateway est le composant qui relie Hermes à votre messagerie. Discord est l'une des options les plus utilisées : les salons et threads permettent de bien organiser les échanges.

  1. Rendez-vous sur le Discord Developer Portal et cliquez sur New Application.
  2. Dans l'onglet Bot, activez les Privileged Gateway Intents suivants puis cliquez sur Save Changes :
    • Message Content Intent (obligatoire : sans lui, le bot reçoit des messages vides)
    • Server Members Intent (obligatoire)
  3. Toujours dans Bot, cliquez sur Reset Token et copiez le token.
  4. Invitez le bot sur votre serveur Discord via l'onglet Installation (ou OAuth2 → URL Generator avec le scope bot).
  5. Récupérez votre identifiant utilisateur Discord : activez le Mode développeur (Paramètres → Avancés), puis clic droit sur votre nom → Copier l'identifiant.

Si vous ne l'avez pas fait dans l'assistant, lancez la configuration de la gateway :

sudo docker compose run --rm hermes gateway setup

Ou ajoutez directement ces lignes dans /opt/hermes/data/.env :

DISCORD_BOT_TOKEN=votre-token-de-bot
DISCORD_ALLOWED_USERS=123456789012345678
Restreignez l'accès au bot

DISCORD_ALLOWED_USERS (ou DISCORD_ALLOWED_ROLES) liste les seules personnes autorisées à donner des ordres à l'agent. Sans cette variable, Hermes refuse tout le monde par sécurité. N'ajoutez que des personnes de confiance : l'agent peut exécuter des commandes sur le serveur.

Par défaut, Hermes répond à tous vos messages privés et, dans les salons, uniquement lorsqu'il est @mentionné.

Démarrage du service

cd /opt/hermes
sudo docker compose up -d
sudo docker compose logs -f --tail=100

restart: unless-stopped relance automatiquement le conteneur après un crash ou un redémarrage du VPS (y compris si l'interface Tailscale n'est pas encore prête au boot : Docker réessaie jusqu'à ce qu'elle le soit).

Vérifiez que le port n'est publié que sur l'adresse Tailscale :

sudo ss -tlnp | grep 9119

La sortie doit afficher 100.x.y.z:9119 et pas 0.0.0.0:9119.

Envoyez ensuite un message privé à votre bot sur Discord : il doit vous répondre.

Accéder à l'interface web

Depuis un appareil connecté à votre réseau Tailscale, ouvrez :

http://100.x.y.z:9119

Connectez-vous avec les identifiants définis dans /opt/hermes/.env. L'interface permet de discuter avec l'agent, consulter les logs, gérer la configuration, les MCP, les profils et les plugins, ainsi qu'un Kanban : vous créez une tâche, l'agent la découpe en sous-tâches confiées à des sous-agents, et les cartes avancent automatiquement.

Arborescence des données

Tout l'état de l'agent se trouve dans /opt/hermes/data (monté sur /opt/data dans le conteneur) :

CheminRôle
config.yamlParamètres globaux : modèles, outils, approbations, délégation
.envClés API (fournisseurs de modèles, Discord, outils web…)
auth.jsonAuthentifications (OAuth, plateformes de messagerie)
SOUL.mdPersonnalité de l'agent (nom, ton, manière d'interagir)
skills/Procédures que l'agent apprend et améliore au fil du temps
cron/Tâches planifiées
state.dbMémoire de l'agent : sessions, historiques… (ne jamais modifier ni copier à chaud)

Personnaliser l'agent

Lui donner une personnalité (SOUL.md)

Le fichier SOUL.md définit le caractère de l'agent et sa manière de s'exprimer. Donnez-lui un nom et un ton : cela rend les échanges plus agréables au quotidien.

sudo nano /opt/hermes/data/SOUL.md
# Janet

Tu es Janet, une assistante serviable, concise et un brin malicieuse.
Tu réponds en français, tu vas droit au but et tu demandes confirmation
avant toute action irréversible.

Choisir les modèles

Un bon compromis consiste à utiliser un modèle rapide et peu coûteux pour la discussion, et un modèle plus solide pour le travail autonome des sous-agents (délégation). Exemple de configuration dans /opt/hermes/data/config.yaml avec OpenRouter :

model:
default: deepseek/deepseek-v4.1-flash
provider: openrouter
base_url: https://openrouter.ai/api/v1
api_mode: chat_completions

delegation:
max_iterations: 50
model: z-ai/glm5.3
provider: openrouter
remarque

Ces modèles sont des exemples issus de l'article au moment de sa rédaction. Le paysage évolue vite : choisissez ceux qui correspondent à votre budget et à vos besoins. Vous pouvez aussi changer de modèle depuis Discord avec la commande /model.

Un second agent pour la relecture de code

Pour éviter qu'un modèle relise son propre travail, créez un profil distinct utilisant un autre modèle (par exemple Claude Opus), puis demandez à votre agent principal de lui faire systématiquement relire le code avant de vous le soumettre :

sudo docker compose run --rm hermes profile create reviewer

Le profil se configure ensuite (modèle, fournisseur) depuis l'interface web, rubrique Profils.

Recherche web

Pour chercher sur Internet de manière autonome, l'agent utilise deux outils :

  • web_search : trouve des liens pertinents. duckduckgo-search fonctionne en local, gratuitement.
  • web_extract : convertit une ou plusieurs pages en Markdown. Tavily propose une clé avec un quota gratuit.

Activez-les depuis l'interface web ou avec sudo docker compose run --rm hermes tools.

Tâches planifiées (crons)

Hermes gère nativement les tâches planifiées. Le plus simple est de les demander directement dans Discord :

/cron add "every 2h" "Vérifie l'état du serveur et préviens-moi en cas d'anomalie"
/cron add "every 1d" "Fais-moi une veille des actualités DevOps et résume les 5 plus importantes"

Idées d'usage : veille automatisée multi-sources, ingestion régulière d'un coffre Obsidian (« second cerveau »), rapports périodiques. Par défaut, une commande dangereuse déclenchée par un cron est refusée (approvals.cron_mode: deny).

Sécurité : les bonnes pratiques

  • Interface web : uniquement via Tailscale (ou autre VPN), jamais sur 0.0.0.0, toujours avec authentification.
  • Approbations : laissez approvals.mode: smart (par défaut) ou passez en manual dans config.yaml. N'utilisez jamais --yolo / approvals.mode: off sur un agent connecté à une messagerie.
  • Accès messagerie : limitez DISCORD_ALLOWED_USERS à vous-même.
  • Socket Docker : ne le montez jamais dans le conteneur.
  • Clés API : utilisez des clés dédiées avec plafond de dépense, et soyez prudent sur les droits accordés aux intégrations (GitHub, e-mail, MCP…).
  • Pare-feu : n'ouvrez que SSH sur l'interface publique. Voir Sécuriser son serveur Linux.

Commandes utiles

ActionCommande (depuis /opt/hermes)
Voir les logssudo docker compose logs -f --tail=100
Redémarrersudo docker compose restart
Arrêtersudo docker compose down
Relancer l'assistantsudo docker compose run --rm hermes setup
Changer de modèlesudo docker compose run --rm hermes model
Diagnosticsudo docker compose run --rm hermes doctor
astuce

Arrêtez le service (docker compose down) avant d'utiliser docker compose run pour modifier la configuration, puis relancez-le avec docker compose up -d.

Mise à jour

L'image étant sans état, il suffit de tirer la nouvelle version et de recréer le conteneur :

cd /opt/hermes
sudo docker compose pull
sudo docker compose up -d

Sauvegarde

Tout l'agent (configuration, clés, mémoire, skills, crons) tient dans /opt/hermes/data. La base state.db ne doit pas être copiée pendant que l'agent tourne : arrêtez-le le temps de l'archive.

cd /opt/hermes
sudo docker compose stop
sudo tar czf /root/hermes-backup-$(date +%F).tar.gz -C /opt/hermes data .env compose.yaml
sudo docker compose start

Conservez ces archives hors du serveur : elles contiennent vos clés API.

En cas de problème

L'interface web ne démarre pas (« no auth providers are registered »)

  • Vérifiez que HERMES_DASHBOARD_BASIC_AUTH_SECRET fait au moins 16 octets (utilisez openssl rand -hex 32).
  • Vérifiez que les trois variables HERMES_DASHBOARD_BASIC_AUTH_* sont bien renseignées dans /opt/hermes/.env.

Le conteneur ne démarre pas

  • Consultez les logs : sudo docker compose logs --tail=200
  • Vérifiez les droits du dossier de données : ls -ln /opt/hermes (propriétaire 10000:10000)
  • Vérifiez que HERMES_BIND_ADDR correspond bien à tailscale ip -4 et que Tailscale est actif : tailscale status
  • Si une erreur de permission apparaît lors de l'initialisation après une mise à jour, commentez temporairement le bloc cap_drop/cap_add pour confirmer, puis ajoutez uniquement la capacité manquante.

Le bot Discord est en ligne mais ne répond pas

  • Vérifiez que Message Content Intent est activé dans le Developer Portal.
  • Vérifiez que votre identifiant figure dans DISCORD_ALLOWED_USERS.
  • Dans un salon, pensez à @mentionner le bot.
  • Redémarrez après toute modification : sudo docker compose restart

« API key not set »

Relancez la configuration du fournisseur : sudo docker compose run --rm hermes model, puis redémarrez le service.

Références