Skip to main content

Installare Hermes Agent (agente IA) su un VPS

Questa guida spiega come installare Hermes Agent su un VPS HostMyServers. Hermes è un framework open source per agenti IA (licenza MIT) sviluppato da Nous Research. A differenza di un assistente di programmazione usato in tempo reale sul proprio computer (Claude Code, OpenCode…), Hermes gira in modo permanente su un server: gli parli dalla tua app di messaggistica (Discord, Telegram, Slack…), lavora in autonomia in background, conserva una memoria delle conversazioni, impara nuove procedure (skills) e può eseguire attività pianificate.

Il deployment si basa su Docker Compose con una configurazione rafforzata, e l'interfaccia web di amministrazione è accessibile solo tramite VPN (Tailscale), mai da Internet.

Fonte

Questa guida si ispira all'esperienza descritta nell'articolo « Hermes : simple hype ou vraie révolution ? » ("Hermes: semplice hype o vera rivoluzione?", damyr.fr, in francese) e alla documentazione ufficiale di Hermes Agent.

Ordina un Server

Hermes non esegue modelli di IA in locale: chiama modelli remoti (OpenRouter, Anthropic, Nous Portal…). Un piccolo VPS è quindi più che sufficiente:

Prerequisiti

  • Accesso SSH come root o utente con sudo
  • Sistema Ubuntu 24.04 LTS o Debian 12/13
  • Un account presso un fornitore di modelli (ad esempio OpenRouter) con una chiave API
  • Un account Tailscale (gratuito per uso personale) per accedere all'interfaccia web
  • Un account Discord (o Telegram, Slack…) per conversare con l'agente

Requisiti di sistema

ComponenteMinimoConsigliato
RAM2 GB4 GB
CPU1 vCPU2 vCPU
Spazio di archiviazione10 GB20 GB
Memoria

L'autore dell'articolo esegue Hermes su un VPS 2 vCPU / 2 GB, ma consiglia almeno 4 GB di RAM non appena si usa l'automazione del browser (Playwright/Chromium) o più sotto-agenti.

Connettiti via SSH, non tramite la console web

Le console dal browser (noVNC) trasmettono male alcuni caratteri (:, @, =) e possono corrompere silenziosamente i comandi e le chiavi API incollati. Usa una vera sessione SSH.

Connessione e aggiornamento del sistema

ssh utente@indirizzo_ip_server
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg openssl

Installazione di Docker

L'immagine Docker ufficiale è il metodo di installazione consigliato da Hermes: l'immagine è senza stato, tutti i dati risiedono in un'unica cartella montata (/opt/data) e un aggiornamento consiste semplicemente nello scaricare una nuova immagine.

Installa Docker Engine e il plugin Compose dal repository ufficiale 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

Verifica l'installazione:

docker --version
docker compose version

Installazione di Tailscale (accesso privato)

L'interfaccia web di Hermes permette di amministrare tutto (chiavi API, configurazione, MCP, plugin, esecuzione di comandi tramite l'agente). Non deve mai essere esposta su Internet: istanze aperte su 0.0.0.0 sono state compromesse da scanner automatici (installazione di chiavi SSH malevole tramite l'agente). La rendiamo quindi accessibile solo dalla tua rete privata Tailscale.

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

Apri il link di autenticazione visualizzato per collegare il server al tuo account Tailscale, poi recupera l'indirizzo IP Tailscale del VPS (intervallo 100.x.y.z):

tailscale ip -4

Annota questo indirizzo: servirà come indirizzo di ascolto per l'interfaccia web. Installa Tailscale anche sul tuo computer o sul tuo telefono per potervi accedere.

Perché associare la porta all'IP Tailscale?

Docker scrive le proprie regole iptables e aggira il firewall UFW per le porte pubblicate. Pubblicare la porta sull'indirizzo Tailscale (e non su 0.0.0.0) garantisce che non sia raggiungibile dall'interfaccia pubblica, qualunque sia lo stato del firewall.

Preparazione delle directory

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

Il container esegue l'agente con l'utente non privilegiato UID/GID 10000: la cartella dei dati deve appartenergli.

File di ambiente

Crea il file /opt/hermes/.env che conterrà l'indirizzo di ascolto e le credenziali dell'interfaccia web:

sudo nano /opt/hermes/.env
# Indirizzo Tailscale del server (risultato di `tailscale ip -4`) — MAI 0.0.0.0
HERMES_BIND_ADDR=100.x.y.z
HERMES_DASHBOARD_PORT=9119

# Credenziali dell'interfaccia web
HERMES_DASHBOARD_BASIC_AUTH_USERNAME=admin
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=PASSWORD
HERMES_DASHBOARD_BASIC_AUTH_SECRET=SECRET

# Limiti di risorse (adatta al tuo VPS: ~1200m per 2 GB, 3g per 4 GB)
HERMES_MEMORY_LIMIT=1200m
HERMES_CPU_LIMIT=1.5

TZ=Europe/Paris

Genera la password e il segreto di sessione, poi riportali nel file:

openssl rand -base64 24 # -> HERMES_DASHBOARD_BASIC_AUTH_PASSWORD
openssl rand -hex 32 # -> HERMES_DASHBOARD_BASIC_AUTH_SECRET
Segreto di almeno 16 byte

HERMES_DASHBOARD_BASIC_AUTH_SECRET deve essere lungo almeno 16 byte. Al di sotto, il modulo di autenticazione non si attiva e l'interfaccia rifiuta di avviarsi con l'errore fuorviante "no auth providers are registered". openssl rand -hex 32 è più che sufficiente. Mantieni stabile questo segreto: cambiarlo invalida le sessioni aperte.

Proteggi il file, contiene dei segreti:

sudo chmod 0600 /opt/hermes/.env

Configurazione Docker Compose

Crea /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

# Nessun processo del container può acquisire nuovi privilegi
security_opt:
- no-new-privileges:true
# Rimuove tutte le capability Linux predefinite...
cap_drop:
- ALL
# ...e restituisce solo quelle necessarie all'inizializzazione del container
cap_add:
- CHOWN
- FOWNER
- DAC_OVERRIDE
- SETUID
- SETGID
- KILL
# Evita errori dovuti a un numero eccessivo di file aperti
ulimits:
nofile:
soft: 4096
hard: 8192

ports:
# Interfaccia web pubblicata SOLO sull'indirizzo Tailscale
- "${HERMES_BIND_ADDR}:${HERMES_DASHBOARD_PORT:-9119}:${HERMES_DASHBOARD_PORT:-9119}"

volumes:
# Tutti i dati dell'agente: config, chiavi, memoria, skills, cron, log
- ./data:/opt/data
# Non montare MAI /var/run/docker.sock: equivarrebbe a dare l'accesso root sull'host

environment:
PUID: "10000"
PGID: "10000"
TZ: "${TZ:-Europe/Paris}"
# Interfaccia web (supervisionata nello stesso container del gateway)
HERMES_DASHBOARD: "1"
HERMES_DASHBOARD_HOST: "0.0.0.0" # solo all'interno del container; lato host, è esposto solo Tailscale
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}"
# Protezioni dell'agente
HERMES_WRITE_SAFE_ROOT: "/opt/data" # l'agente può scrivere solo nella sua cartella dati
HERMES_YOLO_MODE: "0" # i comandi pericolosi restano soggetti ad approvazione

shm_size: "256m"

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

# Evita che un agente molto loquace riempia il disco
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Immagine rafforzata della community

L'autore dell'articolo pubblica una variante dell'immagine ufficiale (DamyrFr/hermes-docker) che aggiunge in particolare rtk (filtraggio dell'output dei comandi per ridurre il consumo di token) e rimuove i binari setuid. La configurazione qui sopra ne riprende le impostazioni di sicurezza con l'immagine ufficiale.

Primo avvio: la procedura guidata di configurazione

Prima di avviare il servizio, esegui una volta la procedura guidata interattiva (interfaccia in modalità testo). Ti chiede il fornitore di modelli e le chiavi API, e propone di configurare la messaggistica (gateway):

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

Durante la procedura guidata:

  1. Fornitore di modelli: scegli ad esempio OpenRouter e incolla la tua chiave API. Alternativa: hermes setup --portal con un abbonamento Nous Portal (oltre 300 modelli e strumenti web inclusi, senza chiavi da gestire).
  2. Strumenti: attiva la ricerca web e l'estrazione di pagine (vedi più avanti).
  3. Messaggistica: configura Discord (vedi sezione successiva) — è l'interfaccia principale con l'agente.
  4. Le impostazioni più oscure possono essere lasciate ai valori predefiniti, tutto è modificabile in seguito.

Le chiavi vengono salvate in /opt/hermes/data/.env e la configurazione in /opt/hermes/data/config.yaml.

Budget sotto controllo con OpenRouter

OpenRouter permette di fissare un limite di spesa per chiave API, azzerabile periodicamente. È ideale per un'istanza personale fatturata a consumo.

Creare il bot Discord (gateway)

Il gateway è il componente che collega Hermes alla tua app di messaggistica. Discord è una delle opzioni più usate: canali e thread permettono di organizzare bene le conversazioni.

  1. Vai sul Discord Developer Portal e clicca su New Application.
  2. Nella scheda Bot, attiva i seguenti Privileged Gateway Intents poi clicca su Save Changes:
    • Message Content Intent (obbligatorio: senza di esso, il bot riceve messaggi vuoti)
    • Server Members Intent (obbligatorio)
  3. Sempre in Bot, clicca su Reset Token e copia il token.
  4. Invita il bot sul tuo server Discord tramite la scheda Installation (oppure OAuth2 → URL Generator con lo scope bot).
  5. Recupera il tuo ID utente Discord: attiva la Modalità sviluppatore (Impostazioni → Avanzate), poi clic destro sul tuo nome → Copia ID utente.

Se non l'hai fatto nella procedura guidata, avvia la configurazione del gateway:

sudo docker compose run --rm hermes gateway setup

Oppure aggiungi direttamente queste righe in /opt/hermes/data/.env:

DISCORD_BOT_TOKEN=il-tuo-token-bot
DISCORD_ALLOWED_USERS=123456789012345678
Limita l'accesso al bot

DISCORD_ALLOWED_USERS (o DISCORD_ALLOWED_ROLES) elenca le sole persone autorizzate a dare ordini all'agente. Senza questa variabile, Hermes rifiuta tutti per sicurezza. Aggiungi solo persone di fiducia: l'agente può eseguire comandi sul server.

Per impostazione predefinita, Hermes risponde a tutti i tuoi messaggi privati e, nei canali, solo quando viene @menzionato.

Avvio del servizio

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

restart: unless-stopped riavvia automaticamente il container dopo un crash o un riavvio del VPS (anche se l'interfaccia Tailscale non è ancora pronta all'avvio: Docker riprova finché non lo è).

Verifica che la porta sia pubblicata solo sull'indirizzo Tailscale:

sudo ss -tlnp | grep 9119

L'output deve mostrare 100.x.y.z:9119 e non 0.0.0.0:9119.

Invia poi un messaggio privato al tuo bot su Discord: deve risponderti.

Accedere all'interfaccia web

Da un dispositivo connesso alla tua rete Tailscale, apri:

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

Accedi con le credenziali definite in /opt/hermes/.env. L'interfaccia permette di conversare con l'agente, consultare i log, gestire la configurazione, gli MCP, i profili e i plugin, oltre a un Kanban: crei un'attività, l'agente la suddivide in sotto-attività affidate a sotto-agenti, e le schede avanzano automaticamente.

Struttura dei dati

Tutto lo stato dell'agente si trova in /opt/hermes/data (montato su /opt/data nel container):

PercorsoRuolo
config.yamlImpostazioni globali: modelli, strumenti, approvazioni, delega
.envChiavi API (fornitori di modelli, Discord, strumenti web…)
auth.jsonAutenticazioni (OAuth, piattaforme di messaggistica)
SOUL.mdPersonalità dell'agente (nome, tono, modo di interagire)
skills/Procedure che l'agente impara e migliora nel tempo
cron/Attività pianificate
state.dbMemoria dell'agente: sessioni, cronologie… (non modificarlo né copiarlo mai a caldo)

Personalizzare l'agente

Dargli una personalità (SOUL.md)

Il file SOUL.md definisce il carattere dell'agente e il suo modo di esprimersi. Dagli un nome e un tono: rende le conversazioni quotidiane più piacevoli.

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

Sei Janet, un'assistente disponibile, concisa e un po' maliziosa.
Rispondi in italiano, vai dritta al punto e chiedi conferma
prima di qualsiasi azione irreversibile.

Scegliere i modelli

Un buon compromesso consiste nell'usare un modello veloce ed economico per la conversazione, e un modello più solido per il lavoro autonomo dei sotto-agenti (delega). Esempio di configurazione in /opt/hermes/data/config.yaml con 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
note

Questi modelli sono esempi tratti dall'articolo al momento della sua stesura. Il panorama evolve rapidamente: scegli quelli adatti al tuo budget e alle tue esigenze. Puoi anche cambiare modello da Discord con il comando /model.

Un secondo agente per la revisione del codice

Per evitare che un modello rilegga il proprio lavoro, crea un profilo distinto che usa un altro modello (ad esempio Claude Opus), poi chiedi al tuo agente principale di fargli rileggere sistematicamente il codice prima di sottoportelo:

sudo docker compose run --rm hermes profile create reviewer

Il profilo si configura poi (modello, fornitore) dall'interfaccia web, nella sezione Profili.

Ricerca web

Per cercare su Internet in autonomia, l'agente usa due strumenti:

  • web_search: trova link pertinenti. duckduckgo-search funziona in locale, gratuitamente.
  • web_extract: converte una o più pagine in Markdown. Tavily offre una chiave con una quota gratuita.

Attivali dall'interfaccia web oppure con sudo docker compose run --rm hermes tools.

Attività pianificate (cron)

Hermes gestisce nativamente le attività pianificate. Il modo più semplice è richiederle direttamente su Discord:

/cron add "every 2h" "Controlla lo stato del server e avvisami in caso di anomalie"
/cron add "every 1d" "Fammi una rassegna delle notizie DevOps e riassumi le 5 più importanti"

Idee di utilizzo: monitoraggio automatico multi-fonte, importazione regolare di un vault Obsidian ("secondo cervello"), report periodici. Per impostazione predefinita, un comando pericoloso avviato da un cron viene rifiutato (approvals.cron_mode: deny).

Sicurezza: le buone pratiche

  • Interfaccia web: solo tramite Tailscale (o altra VPN), mai su 0.0.0.0, sempre con autenticazione.
  • Approvazioni: lascia approvals.mode: smart (predefinito) o passa a manual in config.yaml. Non usare mai --yolo / approvals.mode: off su un agente collegato a una app di messaggistica.
  • Accesso alla messaggistica: limita DISCORD_ALLOWED_USERS a te stesso.
  • Socket Docker: non montarlo mai nel container.
  • Chiavi API: usa chiavi dedicate con un tetto di spesa, e fai attenzione ai permessi concessi alle integrazioni (GitHub, e-mail, MCP…).
  • Firewall: apri solo SSH sull'interfaccia pubblica. Vedi Proteggere il server Linux.

Comandi utili

AzioneComando (da /opt/hermes)
Visualizzare i logsudo docker compose logs -f --tail=100
Riavviaresudo docker compose restart
Arrestaresudo docker compose down
Rieseguire la procedura guidatasudo docker compose run --rm hermes setup
Cambiare modellosudo docker compose run --rm hermes model
Diagnosticasudo docker compose run --rm hermes doctor
tip

Arresta il servizio (docker compose down) prima di usare docker compose run per modificare la configurazione, poi riavvialo con docker compose up -d.

Aggiornamento

Poiché l'immagine è senza stato, basta scaricare la nuova versione e ricreare il container:

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

Backup

L'intero agente (configurazione, chiavi, memoria, skills, cron) è contenuto in /opt/hermes/data. Il database state.db non deve essere copiato mentre l'agente è in esecuzione: arrestalo durante la creazione dell'archivio.

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

Conserva questi archivi fuori dal server: contengono le tue chiavi API.

Risoluzione dei problemi

L'interfaccia web non si avvia ("no auth providers are registered")

  • Verifica che HERMES_DASHBOARD_BASIC_AUTH_SECRET sia lungo almeno 16 byte (usa openssl rand -hex 32).
  • Verifica che le tre variabili HERMES_DASHBOARD_BASIC_AUTH_* siano valorizzate in /opt/hermes/.env.

Il container non si avvia

  • Consulta i log: sudo docker compose logs --tail=200
  • Verifica i permessi della cartella dei dati: ls -ln /opt/hermes (proprietario 10000:10000)
  • Verifica che HERMES_BIND_ADDR corrisponda a tailscale ip -4 e che Tailscale sia attivo: tailscale status
  • Se compare un errore di permessi durante l'inizializzazione dopo un aggiornamento, commenta temporaneamente il blocco cap_drop/cap_add per conferma, poi aggiungi solo la capability mancante.

Il bot Discord è online ma non risponde

  • Verifica che Message Content Intent sia attivato nel Developer Portal.
  • Verifica che il tuo ID sia presente in DISCORD_ALLOWED_USERS.
  • In un canale, ricordati di @menzionare il bot.
  • Riavvia dopo ogni modifica: sudo docker compose restart

"API key not set"

Riesegui la configurazione del fornitore: sudo docker compose run --rm hermes model, poi riavvia il servizio.

Riferimenti