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

146 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Hermes Docker on Kraken
created: '2026-05-23'
updated: '2026-06-04'
type: tech
namespace: personal
tags: [hermes, docker, kraken, infra, how-to]
related:
- "[[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`)
```yaml
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
```bash
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:
```bash
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`).
**Диагностика по порядку**
```bash
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)