hermes installation

hermes
This commit is contained in:
2026-04-20 19:10:28 +02:00
parent edf5b4fda8
commit fc38fb2ab6
6 changed files with 639 additions and 0 deletions
+3
View File
@@ -41,6 +41,8 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
| Nextcloud | Admin Password | `/mnt/user/appdata/secrets/nextcloud_admin_password.txt` -> `NEXTCLOUD_ADMIN_PASSWORD_FILE` | neu |
| nextcloud-postgres | DB Password | `/mnt/user/appdata/secrets/nextcloud_postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | neu |
| Borg UI / Borg | Admin-Login, `SECRET_KEY`, SSH-Keys, Repo-Credentials | persistent unter `/mnt/user/appdata/borg-ui/data/` | aktiv |
| Hermes Agent | Provider-Keys, Bot-Tokens, API-Server-Key | `/mnt/user/appdata/hermes-agent/data/.env` | neu |
| Hermes Agent | SSH-Runner Private Key | `/mnt/user/appdata/secrets/hermes_runner_id_ed25519` -> `/root/.ssh/id_ed25519` | neu |
---
@@ -75,6 +77,7 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
Weitere dokumentierte Secret-Pfade:
- `/mnt/user/appdata/code-server/secrets/password`
- `/mnt/user/appdata/secrets/hermes_runner_id_ed25519`
- `/mnt/user/appdata/traefik/secrets/cloudflare_dns_api_token`
- Borg UI verwaltet Session-Secret, Admin-Login, SSH-Keys und Repo-Credentials in seiner persistenten `/data`-Struktur. Diese Daten liegen nicht im Git, muessen aber gesichert werden.
- `paperless-ngx` ist eine bewusste Ausnahme: DB-Passwort und Redis-URL bleiben aktuell als Komodo Stack Environment Variables hinterlegt, um den stabil laufenden Produktionsstand nicht fuer eine reine Secret-Mechanik-Migration zu riskieren.
+444
View File
@@ -0,0 +1,444 @@
# Hermes Agent for the Homelab
## Phase 1 - Documentation Analysis
### What Hermes Agent is
Hermes Agent is an autonomous AI agent from Nous Research with:
- CLI/TUI usage
- a messaging gateway for Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant and others
- persistent memory and session search under `~/.hermes/`
- scheduled jobs via the gateway
- multiple terminal backends (`local`, `docker`, `ssh`, `modal`, `daytona`, `singularity`)
The official docs describe it as an agent that lives on a server, remembers what it learns, and can be reached from different chat surfaces.
### Official installation paths
Officially documented paths:
- Linux/macOS/WSL2 installer via `curl ... install.sh | bash`
- official Docker image `nousresearch/hermes-agent`
- Nix / NixOS module
- source / development install from the Git repository
For this repository and your current Unraid + Compose operating model, the Docker image is the cleanest officially documented runtime path.
### Requirements from the docs
- Git is the only prerequisite for the standard installer
- the installer provisions `uv`, Python 3.11, Node.js v22, `ripgrep`, and `ffmpeg`
- Hermes requires an LLM with at least 64k context
- at least one provider must be configured
- API keys and secrets belong in `~/.hermes/.env`
- non-secret settings belong in `~/.hermes/config.yaml`
### Operating modes relevant for homelab use
- interactive CLI/TUI
- persistent messaging gateway
- optional OpenAI-compatible API server
- optional dashboard
- terminal execution backend selection
- Home Assistant integration via token plus event filters
### Security-relevant findings from the docs
- the gateway denies unknown users by default unless they are allowlisted or paired
- dangerous command approval applies to `local` and `ssh` terminal backends
- the official Docker terminal backend is considered a strong isolation boundary and skips dangerous-command approval
- the API server is localhost-only by default and becomes high-risk if bound to `0.0.0.0` without auth
- persistent memory is injected into the prompt and is security-scanned before acceptance
- the runtime Docker container itself runs as root by default according to the official Docker docs
- the official Docker docs explicitly warn against running two gateway containers against the same data directory
### Homelab relevance
Useful:
- Docker runtime container
- messaging gateway
- API server only on an internal network
- Home Assistant integration
- persistent memory, sessions, cron, logs
- SSH backend for separating tool execution from the NAS
- OpenAI-compatible backends such as OpenAI API and Ollama
Usually not first choice for this homelab:
- native installer directly on the NAS host
- mounting the host Docker socket into the Hermes runtime container
- internet-exposed API server
- `local` backend on the NAS host
- browser-heavy features unless explicitly needed
## Phase 2 - Architecture Decision
### Model A - Docker/Compose on NAS, `terminal.backend=local`
| Criterion | Assessment |
|---|---|
| Stability | High |
| Security | Medium |
| Wartability | High |
| Homelab integration | Very high |
| Complexity | Low |
Pros:
- fully official Docker runtime path
- best match to current Unraid/Compose/GitOps model
- easiest deployment and upgrade
Cons:
- terminal commands run inside the main Hermes service container
- no second isolation layer between agent runtime and tool execution
- package installs done by the agent are not a clean, persistent operating model
### Model B - Native Hermes install in dedicated Linux VM/LXC, `terminal.backend=docker`
| Criterion | Assessment |
|---|---|
| Stability | High |
| Security | Very high |
| Wartability | Medium |
| Homelab integration | Medium |
| Complexity | High |
Pros:
- closest match to the official security guidance for a production gateway
- clean separation between Hermes runtime and Docker sandboxed commands
- no NAS Docker socket exposed to a chat-facing container
Cons:
- separate lifecycle from your current Compose-centric homelab
- more moving parts to patch, back up, and monitor
### Model C - Docker/Compose gateway on NAS, `terminal.backend=ssh` to dedicated Linux runner
| Criterion | Assessment |
|---|---|
| Stability | High |
| Security | High |
| Wartability | High |
| Homelab integration | High |
| Complexity | Medium |
Pros:
- official Docker runtime path for Hermes itself
- official SSH backend for command execution
- no host Docker socket in the gateway container
- clean separation between chat-facing service and execution environment
- fits your existing NAS/Compose/GitOps model
Cons:
- requires a dedicated runner VM/LXC
- dangerous-command approval still applies on the SSH backend
## Phase 3 - Clear Recommendation
### Recommended target image
Use **Model C**:
- Hermes gateway and dashboard as official Docker containers on the NAS
- terminal execution via the official `ssh` backend to a dedicated Linux runner
- primary LLM via GPT/OpenAI API
- Ollama on the gaming PC as optional secondary provider, not as required infrastructure
- no Docker socket inside the Hermes gateway container
- dashboard behind Traefik + Authelia
- API server only on the internal `hermes_net`
### Why this is the best fit here
This gives you the official containerized deployment the docs support, while avoiding the least-auditable shortcut: giving a chat-facing agent container direct host Docker control.
For the model layer, the most robust setup for your homelab is a hybrid:
- OpenAI API as the primary inference backend
- Ollama on the gaming PC as an optional alternate backend
Reason:
- Hermes officially supports OpenAI-compatible endpoints, including Ollama
- your gaming PC is useful compute, but it should not be the only dependency for the agent's baseline availability
- with this split, Hermes still works when the gaming PC is off
Important inference:
The official docs clearly distinguish between:
1. running Hermes **in** Docker
2. using Docker as the **terminal backend**
I did **not** find an official deployment pattern that explicitly documents mounting the NAS Docker socket into the Hermes runtime container so that the runtime container itself manages sibling Docker sandboxes. The official runtime image docs list Python, Node, Playwright, `ripgrep`, and `ffmpeg`, but not the Docker CLI. Based on that, I treat "runtime container + host docker.sock for terminal backend" as a weakly documented path and do not recommend it for your production homelab.
## Phase 4 - Implementation
### Repository files
- `ops/hermes-agent/docker-compose.yml`
- `ops/hermes-agent/stack.env.example`
- `ops/hermes-agent/hermes.env.example`
- `ops/hermes-agent/config/hermes/config.yaml`
### Host paths used by this setup
- `/mnt/user/appdata/hermes-agent/data`
- `/mnt/user/appdata/hermes-agent/ssh`
- `/mnt/user/appdata/secrets/hermes_runner_id_ed25519`
### Deployment layout
- `hermes-gateway` stores state in `/opt/data`
- repo-managed `config.yaml` is bind-mounted read-only into `/opt/data/config.yaml`
- dashboard reads the same data volume but has no direct access to the SSH private key
- only the dashboard joins `frontend_net`
- the gateway stays off `frontend_net` and only exposes port `8642` internally on `hermes_net`
### Reverse proxy
Use Traefik only for the dashboard.
- yes for the dashboard
- no for the gateway API by default
- no public publish of `8642`
### Docker socket
Do **not** mount `/var/run/docker.sock`.
### Runner preparation
On the dedicated Linux VM/LXC:
```bash
sudo useradd --create-home --shell /bin/bash hermes
sudo mkdir -p /srv/hermes-workspace
sudo chown hermes:hermes /srv/hermes-workspace
sudo chmod 755 /srv/hermes-workspace
sudo -u hermes mkdir -p /home/hermes/.ssh
sudo -u hermes chmod 700 /home/hermes/.ssh
```
Add the NAS-side public key to `/home/hermes/.ssh/authorized_keys`:
```bash
sudo -u hermes sh -c 'cat >> /home/hermes/.ssh/authorized_keys'
sudo -u hermes chmod 600 /home/hermes/.ssh/authorized_keys
```
Recommended runner packages:
```bash
sudo apt-get update
sudo apt-get install -y bash ca-certificates curl git jq python3 python3-venv ripgrep ffmpeg
```
Do **not** grant `sudo` unless you have a concrete use case and a reviewed sudoers policy.
### NAS-side prep
```bash
mkdir -p /mnt/user/appdata/hermes-agent/data
mkdir -p /mnt/user/appdata/hermes-agent/ssh
chmod 700 /mnt/user/appdata/hermes-agent/ssh
```
Create the runner keypair on the NAS and keep the private key outside Git:
```bash
ssh-keygen -t ed25519 -f /mnt/user/appdata/secrets/hermes_runner_id_ed25519 -C hermes-runner
chmod 600 /mnt/user/appdata/secrets/hermes_runner_id_ed25519
chmod 644 /mnt/user/appdata/secrets/hermes_runner_id_ed25519.pub
```
### First-time configuration
1. Copy `stack.env.example` to `stack.env`.
2. Copy `hermes.env.example` to `/mnt/user/appdata/hermes-agent/data/.env`.
3. Fill the OpenAI API key and your chosen OpenAI model ID as the primary model.
4. Optionally add the Ollama endpoint from the gaming PC as an alternate model profile.
5. Fill API server key, messaging token(s), and SSH runner settings.
4. Deploy the stack.
Example local validation before shipping to Komodo:
```bash
docker compose --env-file stack.env config
docker compose --env-file stack.env up -d
```
## Phase 5 - Validation
### 1. Container health
```bash
docker compose --env-file stack.env ps
docker compose --env-file stack.env logs --tail=100 hermes-gateway
docker compose --env-file stack.env logs --tail=100 hermes-dashboard
```
### 2. API server / dashboard path
From the NAS:
```bash
docker exec hermes-gateway python3 -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8642/health', timeout=3).read().decode())"
```
Expected: `{"status":"ok"}` or equivalent health JSON.
### 3. Hermes self-check
```bash
docker exec -it hermes-gateway hermes doctor
docker exec -it hermes-gateway hermes config
```
Use `hermes doctor` first whenever provider or backend setup is suspect.
### 4. SSH backend check
Inside Hermes, issue a harmless command such as:
```text
Run `hostname` and `pwd`.
```
Expected:
- hostname is the runner VM/LXC, not the NAS
- working directory is `/srv/hermes-workspace`
### 5. Model/provider check
Inside Hermes:
```text
Tell me which provider and model you are using.
```
Then run one simple, no-tool prompt and one tool-using prompt. If the base provider works but web tools fail, the likely issue is missing web-tool credentials rather than a broken main model.
Recommended operator check:
- first validate with the primary GPT/OpenAI backend
- then temporarily switch to the Ollama endpoint and confirm Hermes can still answer and call tools
- treat Ollama as optional capacity, not as required uptime dependency
### 6. Persistence / memory check
After at least one session and one saved memory:
```bash
ls -la /mnt/user/appdata/hermes-agent/data
ls -la /mnt/user/appdata/hermes-agent/data/memories
```
Check for:
- `config.yaml`
- `.env`
- `memories/`
- `sessions/`
- `logs/`
- `state.db`
### 7. Home Assistant check
If `HASS_TOKEN` is set:
- verify Hermes sees the `homeassistant` toolset
- ask it to list a few entities
- trigger a watched entity and confirm the gateway receives an event
If no HA events arrive, first check `watch_domains`, `watch_entities`, and `ignore_entities`.
### Common misconfiguration signals
- dashboard unhealthy: API server not enabled or not reachable on `0.0.0.0:8642`
- Hermes cannot run terminal commands: SSH key, host, user, or remote permissions are wrong
- web tools missing: no supported web-search provider configured
- HA tools missing: `HASS_TOKEN` not set
- unknown users can message the bot: allowlist or pairing policy not configured
## Phase 6 - Hardening
### Minimal rights
- keep `cap_drop: [ALL]`
- keep `no-new-privileges:true`
- keep the gateway off `frontend_net`
- do not mount the Docker socket
- do not run Hermes directly on the NAS host
- do not grant the runner user blanket `sudo`
### Secrets handling
- keep provider keys and bot tokens in `/mnt/user/appdata/hermes-agent/data/.env`
- keep the SSH private key in `/mnt/user/appdata/secrets/hermes_runner_id_ed25519`
- limit file permissions to `600`
- if Komodo injects secrets as stack env vars, use that only where Hermes upstream requires env-only config
### Tool isolation
- terminal execution goes only to the dedicated runner
- use the Home Assistant token only if HA control is needed
- reduce enabled tools with `hermes tools` once the base deployment is stable
### Network boundaries
- expose only the dashboard through Traefik
- keep `8642` internal unless you intentionally integrate a frontend such as Open WebUI
- if you later expose the API server beyond `hermes_net`, keep bearer auth enabled and scope it tightly
### Model strategy
- keep GPT/OpenAI as the default production path
- use Ollama when you explicitly want local inference or lower marginal cost
- do not design the base service around the assumption that the gaming PC is always on
### Updates
- current official Docker tag used here: `nousresearch/hermes-agent:v2026.4.16`
- update deliberately, test with `hermes doctor`, then roll forward
- avoid `latest` in production if you want reproducibility
### Backups
Back up at least:
- `/mnt/user/appdata/hermes-agent/data/.env`
- `/mnt/user/appdata/hermes-agent/data/config.yaml`
- `/mnt/user/appdata/hermes-agent/data/auth.json`
- `/mnt/user/appdata/hermes-agent/data/memories/`
- `/mnt/user/appdata/hermes-agent/data/sessions/`
- `/mnt/user/appdata/hermes-agent/data/cron/`
- `/mnt/user/appdata/hermes-agent/ssh/known_hosts`
- `/mnt/user/appdata/secrets/hermes_runner_id_ed25519`
## Official sources used
- Repository README: <https://github.com/NousResearch/hermes-agent>
- Installation: <https://hermes-agent.nousresearch.com/docs/getting-started/installation/>
- Quickstart: <https://hermes-agent.nousresearch.com/docs/getting-started/quickstart/>
- Configuration: <https://hermes-agent.nousresearch.com/docs/user-guide/configuration/>
- Docker: <https://hermes-agent.nousresearch.com/docs/user-guide/docker/>
- Security: <https://hermes-agent.nousresearch.com/docs/user-guide/security/>
- Tools and Toolsets: <https://hermes-agent.nousresearch.com/docs/user-guide/features/tools/>
- Built-in tools reference: <https://hermes-agent.nousresearch.com/docs/reference/tools-reference/>
- Persistent memory: <https://hermes-agent.nousresearch.com/docs/user-guide/features/memory/>
- Messaging gateway: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/>
- Home Assistant integration: <https://hermes-agent.nousresearch.com/docs/user-guide/messaging/homeassistant/>
- AI providers: <https://hermes-agent.nousresearch.com/docs/integrations/providers/>
- FAQ: <https://hermes-agent.nousresearch.com/docs/reference/faq/>
- Nix / NixOS setup: <https://hermes-agent.nousresearch.com/docs/getting-started/nix-setup/>
- Official Docker tags: <https://hub.docker.com/r/nousresearch/hermes-agent/tags>
@@ -0,0 +1,51 @@
model:
provider: ${HERMES_MODEL_PROVIDER}
default: ${HERMES_MODEL_NAME}
base_url: ${HERMES_MODEL_BASE_URL}
compression:
enabled: true
threshold: 0.50
target_ratio: 0.20
protect_last_n: 20
memory:
memory_enabled: true
user_profile_enabled: true
nudge_interval: 10
flush_min_turns: 6
session_reset:
mode: both
idle_minutes: 720
at_hour: 4
display:
tool_progress: new
tool_progress_command: false
background_process_notifications: result
agent:
max_turns: 60
verbose: false
reasoning_effort: medium
terminal:
backend: ssh
cwd: /srv/hermes-workspace
timeout: 180
persistent_shell: true
platforms:
homeassistant:
enabled: true
extra:
watch_domains:
- climate
- binary_sensor
- alarm_control_panel
ignore_entities:
- sensor.uptime
- sensor.cpu_usage
- sensor.memory_usage
cooldown_seconds: 30
+70
View File
@@ -0,0 +1,70 @@
services:
hermes-gateway:
image: nousresearch/hermes-agent:v2026.4.16
container_name: hermes-gateway
restart: unless-stopped
init: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
pids_limit: 256
environment:
TZ: ${TZ:-Europe/Berlin}
HERMES_HOME: /opt/data
volumes:
- /mnt/user/appdata/hermes-agent/data:/opt/data
- /mnt/user/appdata/hermes-agent/ssh:/root/.ssh
- /mnt/user/appdata/secrets/hermes_runner_id_ed25519:/root/.ssh/id_ed25519:ro
- ./config/hermes/config.yaml:/opt/data/config.yaml:ro
expose:
- "8642"
networks:
- hermes_net
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8642/health', timeout=3).read()"]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s
hermes-dashboard:
image: nousresearch/hermes-agent:v2026.4.16
container_name: hermes-dashboard
restart: unless-stopped
init: true
command: dashboard --host 0.0.0.0
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
pids_limit: 128
depends_on:
hermes-gateway:
condition: service_healthy
environment:
TZ: ${TZ:-Europe/Berlin}
HERMES_HOME: /opt/data
GATEWAY_HEALTH_URL: http://hermes-gateway:8642
volumes:
- /mnt/user/appdata/hermes-agent/data:/opt/data:ro
- ./config/hermes/config.yaml:/opt/data/config.yaml:ro
networks:
- hermes_net
- frontend_net
labels:
- traefik.enable=true
- traefik.docker.network=frontend_net
- traefik.http.routers.hermes-dashboard.rule=Host(`${HERMES_DASHBOARD_HOST}`)
- traefik.http.routers.hermes-dashboard.entrypoints=websecure
- traefik.http.routers.hermes-dashboard.tls=true
- traefik.http.routers.hermes-dashboard.tls.certresolver=le
- traefik.http.routers.hermes-dashboard.middlewares=authelia@file,secure-headers@file
- traefik.http.services.hermes-dashboard.loadbalancer.server.port=9119
networks:
frontend_net:
external: true
hermes_net:
name: hermes_net
driver: bridge
+69
View File
@@ -0,0 +1,69 @@
# Copy to:
# /mnt/user/appdata/hermes-agent/data/.env
#
# This file is read by Hermes itself inside /opt/data/.env.
# Do not commit the real file.
# -----------------------------------------------------------------------------
# API server / dashboard integration
# -----------------------------------------------------------------------------
API_SERVER_ENABLED=true
API_SERVER_HOST=0.0.0.0
API_SERVER_PORT=8642
API_SERVER_KEY=replace-with-a-long-random-secret
# -----------------------------------------------------------------------------
# Primary model selection
# Recommended production default for this homelab:
# use OpenAI-compatible GPT access as the primary provider.
#
# Hermes' official provider docs explicitly support OpenAI-compatible endpoints.
# We therefore use the documented custom-endpoint path for api.openai.com.
#
# Choose one provider/model pair and fill the matching credentials below.
# Hermes requires at least 64k context window.
# -----------------------------------------------------------------------------
HERMES_MODEL_PROVIDER=custom
HERMES_MODEL_NAME=your-openai-model-id
HERMES_MODEL_BASE_URL=https://api.openai.com/v1
# Provider credentials
OPENROUTER_API_KEY=
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
# Optional: switch the main model to Ollama on the gaming PC
# HERMES_MODEL_PROVIDER=custom
# HERMES_MODEL_NAME=qwen3.5:32b
# HERMES_MODEL_BASE_URL=http://192.168.178.103:11434/v1
# OPENAI_API_KEY=ollama
# Optional: keep a note of your preferred GPT model here for operations docs
# Example only - set to the exact OpenAI model ID you actually use:
# HERMES_PRIMARY_LABEL=gpt-via-openai-api
# Optional: extra web-search provider for web tools
TAVILY_API_KEY=
# -----------------------------------------------------------------------------
# Messaging gateway
# Enable only the platforms you actually use.
# -----------------------------------------------------------------------------
TELEGRAM_BOT_TOKEN=
TELEGRAM_ALLOWED_USERS=
# -----------------------------------------------------------------------------
# Home Assistant integration
# HASS_TOKEN enables the homeassistant toolset automatically.
# -----------------------------------------------------------------------------
HASS_TOKEN=
HASS_URL=http://homeassistant.local:8123
# -----------------------------------------------------------------------------
# SSH terminal backend
# Hermes will execute terminal commands on the dedicated runner.
# -----------------------------------------------------------------------------
TERMINAL_SSH_HOST=192.168.178.250
TERMINAL_SSH_USER=hermes
TERMINAL_SSH_PORT=22
TERMINAL_SSH_KEY=/root/.ssh/id_ed25519
+2
View File
@@ -0,0 +1,2 @@
TZ=Europe/Berlin
HERMES_DASHBOARD_HOST=hermes.kaleschke.info