Files
obsidian-vault/family/how-to/hermes-docker-kraken.md
T

6.1 KiB
Raw Blame History

title, created, updated, type, namespace, tags, related
title created updated type namespace tags related
Hermes Docker on Kraken 2026-05-23 2026-06-04 tech personal
hermes
docker
kraken
infra
how-to
tech/kraken-network
concepts/hermes-deployment-patterns
tech/hermes-kraken-api

Hermes Docker on Kraken

Key Rule

Hermes runs via docker compose from the hermes-build/ directory.

Directory Layout (on Kraken)

/srv/.../docker/
├── hermes-build/          ← build + run from here
│   ├── Dockerfile         ← clones upstream NousResearch/hermes-agent
│   ├── docker-compose.yml ← canonical compose file
│   ├── config.yaml        ← unused at build time (runtime config is in hermes/config/)
│   └── .env               ← all secrets/API keys (sourced by compose)
└── hermes/
    └── config/            ← mounted as /opt/data (HERMES_HOME) inside container

Compose File (hermes-build/docker-compose.yml)

services:
  kraken:
    build:
      context: .
      dockerfile: Dockerfile
    image: hermes-kraken:latest
    container_name: hermes-kraken
    stdin_open: true
    tty: true
    restart: unless-stopped
    volumes:
      - /srv/.../docker/hermes/config:/opt/data
      - /home/kraken/obsidian:/vault:rw
    environment:
      - HERMES_ALLOW_ROOT_GATEWAY=1
    env_file:
      - .env
    command: gateway
    network_mode: host

Managing the Container

cd /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/hermes-build

docker compose up -d          # start
docker compose down           # stop
docker compose pull           # pull new image (if from registry)
docker compose build          # rebuild image from Dockerfile
docker compose restart        # restart
docker compose logs -f        # follow logs

Image

Built locally from Dockerfile — clones upstream NousResearch/hermes-agent (--depth=1 from main). Not a custom fork. To update Hermes:

cd /srv/.../docker/hermes-build
docker compose build --no-cache
docker compose up -d

Volumes

Host path Container path Purpose
hermes/config/ /opt/data HERMES_HOME — config, sessions, skills, memory
/home/kraken/obsidian /vault Obsidian vault read/write access

SSH из контейнера → хост (диагностика и фиксы)

Перенесено из удалённого скилла kraken-omv-maintenance / kraken-docker-ssh. Актуальные пути и фиксы для случая, когда ssh kraken-host изнутри контейнера hermes-kraken не работает.

Архитектура

Container (hermes-kraken)
  uid=10000 (dropped from root by entrypoint)
  HOME=/opt/data
  ~/.ssh/config = /opt/data/.ssh/config  (bind mount from host)
  /etc/ssh/ssh_config — bind mount (полный /etc/ssh/)

Host (Kraken RPi5)
  User kraken (uid=1000) owns /home/kraken/.ssh/
  /home/kraken/.ssh/id_ed25519 — закрытый ключ (обязательно 600)
  /home/kraken/.ssh/authorized_keys — должен содержать публичный ключ

Fixed points (НЕ менять)

  1. В compose не задавать user:, entrypoint:, HERMES_UID/GID — entrypoint сам сбрасывает uid (image defaults).
  2. Публичный ключ на хост один раз: ssh-copy-id kraken@<host>.
  3. Закрытый ключ на хосте обязан быть 600: ssh kraken@<host> "chmod 600 /home/kraken/.ssh/id_ed25519" — OpenSSH 10.x (Bookworm) отвергает 644.
  4. В /etc/passwd контейнера должен быть kraken:x:1000 — не выставлять user: в compose.
  5. SSH config обязан лежать в $HOME/.ssh/config ($HOME=/opt/data/opt/data/.ssh/config).

Диагностика по порядку

ssh kraken@<host> "echo OK && hostname"          # доступен ли хост
ssh kraken@<host> "sudo docker ps --filter name=hermes-kraken --format '{{.Names}} {{.Status}}'"
# изнутри контейнера на хост (loopback алиас kraken-host)
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -o ConnectTimeout=5 kraken-host 'echo HELLO'"
# verbose — какие конфиги читает SSH
ssh kraken@<host> "sudo docker exec hermes-kraken ssh -v kraken-host 'echo HELLO' 2>&1 | grep -E 'config|debug1.*/ssh|Host|connect|Permission|authenticate|bad|owner' | head -15"
ssh kraken@<host> "sudo docker exec hermes-kraken getent passwd 1000"          # uid 1000 в passwd?
ssh kraken@<host> "sudo docker exec hermes-kraken ls -la /opt/data/.ssh/id_ed25519"
ssh kraken@<host> "sudo docker exec hermes-kraken cat /opt/data/.ssh/config"
ssh kraken@<host> "sudo docker exec hermes-kraken sh -c 'echo HOME=\$HOME; ls -la \"\$HOME/.ssh/config\"'"

Pitfalls

  • Не менять user: в compose — entrypoint должен стартовать как root, чтобы сделать chown.
  • Не chown'ить /opt/data на 1000:1000 — entrypoint делает chown -R hermes:hermes (uid 10000).
  • Не ставить 644 на закрытый ключ.
  • НЕ использовать Include ~/.ssh/config в системном /etc/ssh/ssh_config — OpenSSH не резолвит ~ в системных Include.
  • Если $HOME=/opt/data, а конфиг живёт в /opt/data/home/.ssh/ — SSH его не прочитает (путь не совпадает).
  • Может быть несколько пар ключей: bind mount приносит хост-ключ, а агент может иметь свой в /opt/data/home/.ssh/.
  • passwd сбрасывается при пересоздании контейнера.
  • Полный mount /etc/ssh/ перезаписывает и host keys тоже.

Notes

  • network_mode: host — port 8642 is directly on the Kraken host, no port mapping needed
  • HERMES_ALLOW_ROOT_GATEWAY=1 — required since container runs as root
  • All secrets in hermes-build/.env (not committed)