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.
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:
- VPS Performance - Ideale per un'istanza personale
- VPS NVMe - Ottimo rapporto qualità/prezzo
- Server dedicati Eco - Per più agenti/profili o automazione intensiva del browser
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
| Componente | Minimo | Consigliato |
|---|---|---|
| RAM | 2 GB | 4 GB |
| CPU | 1 vCPU | 2 vCPU |
| Spazio di archiviazione | 10 GB | 20 GB |
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.
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.
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
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"
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:
- Fornitore di modelli: scegli ad esempio OpenRouter e incolla la tua chiave API. Alternativa:
hermes setup --portalcon un abbonamento Nous Portal (oltre 300 modelli e strumenti web inclusi, senza chiavi da gestire). - Strumenti: attiva la ricerca web e l'estrazione di pagine (vedi più avanti).
- Messaggistica: configura Discord (vedi sezione successiva) — è l'interfaccia principale con l'agente.
- 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.
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.
- Vai sul Discord Developer Portal e clicca su New Application.
- 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)
- Sempre in Bot, clicca su Reset Token e copia il token.
- Invita il bot sul tuo server Discord tramite la scheda Installation (oppure OAuth2 → URL Generator con lo scope
bot). - 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
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):
| Percorso | Ruolo |
|---|---|
config.yaml | Impostazioni globali: modelli, strumenti, approvazioni, delega |
.env | Chiavi API (fornitori di modelli, Discord, strumenti web…) |
auth.json | Autenticazioni (OAuth, piattaforme di messaggistica) |
SOUL.md | Personalità dell'agente (nome, tono, modo di interagire) |
skills/ | Procedure che l'agente impara e migliora nel tempo |
cron/ | Attività pianificate |
state.db | Memoria 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
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-searchfunziona 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 amanualinconfig.yaml. Non usare mai--yolo/approvals.mode: offsu un agente collegato a una app di messaggistica. - Accesso alla messaggistica: limita
DISCORD_ALLOWED_USERSa 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
| Azione | Comando (da /opt/hermes) |
|---|---|
| Visualizzare i log | sudo docker compose logs -f --tail=100 |
| Riavviare | sudo docker compose restart |
| Arrestare | sudo docker compose down |
| Rieseguire la procedura guidata | sudo docker compose run --rm hermes setup |
| Cambiare modello | sudo docker compose run --rm hermes model |
| Diagnostica | sudo docker compose run --rm hermes doctor |
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_SECRETsia lungo almeno 16 byte (usaopenssl 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(proprietario10000:10000) - Verifica che
HERMES_BIND_ADDRcorrisponda atailscale ip -4e 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_addper 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.