Запуск Hermes AI в Docker Compose
Опубликовано:
В инструкции развернем Hermes Agent в Docker Compose: gateway, веб-дашборд и OpenAI-совместимый API на одном контейнере. На выходе — локальный агент с постоянным хранилищем данных и входом в дашборд по логину и паролю.
Образ nousresearch/hermes-agent, данные на хосте в /opt/hermes/data. Для публичного интернета basic auth недостаточно — тогда нужен OAuth через Nous Portal или reverse-proxy с TLS.
Что понадобится перед установкой
Готовим пароли и ключи
Описываем сервис в docker-compose.yml
Запускаем контейнер и мастер настройки
Проверяем, что агент отвечает
Подключаем LLM через ProxyAPI
Обновление и остановка агента
Если что-то пошло не так
Похожие инструкции
Что понадобится перед установкой
- Linux-сервер с Docker Engine и Docker Compose plugin.
- Свободные порты 8642 (API/health) и 9119 (dashboard).
- Доступ к Docker Hub для образа nousresearch/hermes-agent.
Проверим, что Docker и Compose уже установлены и доступны:
docker --version
docker-compose version
* если команд нет — установите Docker Engine и плагин Compose по инструкции Как установить Docker на Linux RPM или DEB.
Готовим пароли и ключи
Создадим каталог для данных агента и перейдем в него:
mkdir -p /opt/hermes/data && cd /opt/hermes
* конфиг агента, сессии и логи — в каталоге data/ (внутри контейнера — /opt/data).
Дашборду и API нужны свои пароли и ключи, поэтому сгенерируем их заранее. Сначала пароль для входа в дашборд:
openssl rand -base64 24
* сохраните вывод — это пароль дашборда (HERMES_DASHBOARD_BASIC_AUTH_PASSWORD).
Теперь секрет для подписи сессий:
openssl rand -base64 32
* сохраните вывод — секрет подписи сессий (HERMES_DASHBOARD_BASIC_AUTH_SECRET). Без него после перезапуска контейнера все сессии сбросятся.
И отдельный ключ для доступа к OpenAI-совместимому API:
openssl rand -hex 32
* сохраните вывод — ключ OpenAI-совместимого API (API_SERVER_KEY, минимум 8 символов).
Все три значения впишем в файл .env, который Compose подхватит автоматически:
vi .env
TZ=Europe/Moscow
HERMES_VER=v2026.7.30
HERMES_DASHBOARD=1
HERMES_DASHBOARD_BASIC_AUTH_USERNAME=admin
HERMES_DASHBOARD_BASIC_AUTH_PASSWORD=вставить-пароль-из-openssl
HERMES_DASHBOARD_BASIC_AUTH_SECRET=вставить-секрет-из-openssl
API_SERVER_ENABLED=true
API_SERVER_HOST=0.0.0.0
API_SERVER_KEY=вставить-ключ-из-openssl
API_SERVER_CORS_ORIGINS=*
* где:
- TZ — часовой пояс контейнера; замените Europe/Moscow на свой (полный список — в базе tz database, например Europe/Berlin или Asia/Almaty).
- HERMES_VER — версия гермеса. Актуальный тег смотрим на Docker Hub.
- HERMES_DASHBOARD — включает веб-дашборд внутри того же контейнера (порт 9119).
- HERMES_DASHBOARD_BASIC_AUTH_* — логин, пароль и секрет для basic auth. На не-loopback bind без провайдера авторизации дашборд не стартует.
- API_SERVER_ENABLED / HOST / KEY — OpenAI-совместимый API и /health на порту 8642.
- API_SERVER_CORS_ORIGINS — разрешенные origin для браузерных клиентов; * — для тестов в доверенной сети.
Файл содержит пароли и ключи, поэтому ограничим права доступа к нему:
chmod 600 .env
Ключи LLM (OpenAI, Anthropic и т.п.) и токены мессенджеров тоже кладутся в .env или задаются интерактивно на шаге setup ниже. Не давайте никому доступ к этому файлу.
Описываем сервис в docker-compose.yml
Создадим файл docker-compose.yml с описанием контейнера, портов и тома для данных:
vi docker-compose.yml
services:
hermes:
image: nousresearch/hermes-agent:${HERMES_VER}
container_name: hermes
hostname: hermes
restart: unless-stopped
command: gateway run
ports:
- "8642:8642"
- "9119:9119"
volumes:
- ./data:/opt/data
environment:
TZ: Europe/Moscow
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8642/health')\""]
interval: 30s
timeout: 5s
retries: 5
start_period: 60s
* где:
- image — зафиксируйте рабочий тег вместо latest; актуальный смотрите на Docker Hub / в релизах Hermes Agent.
- command: gateway run — режим gateway под s6: автоперезапуск процесса и дашборд рядом при HERMES_DASHBOARD=1.
- 8642 — API и /health; 9119 — веб-дашборд.
- volumes — bind-mount каталога data/; не монтируйте один и тот же каталог в два контейнера Hermes одновременно.
- healthcheck — опрос http://127.0.0.1:8642/health изнутри контейнера (нужен включенный API server).
Запускаем контейнер и мастер настройки
Перед первым запуском пройдем интерактивный мастер настройки агента:
docker-compose run --rm hermes setup
* интерактивный мастер пишет конфиг в data/. Для работы с Nous Portal внутри контейнера можно выполнить hermes setup --portal. Команду вводите по SSH, а не через веб-консоль VPS — иначе легко испортить спецсимволы в путях и ключах.
Мастер задаст по очереди несколько вопросов о режиме работы и подключаемых мессенджерах. Для базовой настройки с Telegram отвечаем на них так:
Setup mode: Quick
Deployment: Local
Set up messaging now (recommended): Yes
Platform: Telegram
Number of bots: 1
Telegram bot token: вставляем токен, полученный у @BotFather
Allowed user IDs (comma-separated, leave empty for open access): оставляем пустым или указываем свои ID
Confirm: Y
* токен бота получают у @BotFather в Telegram командой /newbot. Пустое поле Allowed user IDs открывает доступ к боту всем, кто найдет его в Telegram — для приватного бота укажите свой числовой ID.
После настройки поднимем контейнер в фоновом режиме:
docker-compose up -d
Проверим, что контейнер запустился:
docker-compose ps
* у сервиса hermes ожидаем Up и со временем healthy.
Посмотрим логи запуска в реальном времени:
docker-compose logs -f --tail=100
* выход из follow — Ctrl+C. В логах не должно быть отказа дашборда из-за отсутствия auth-провайдера.
Проверяем, что агент отвечает
Убедимся, что API-сервер поднялся и отвечает на health-запрос:
curl -fsS http://127.0.0.1:8642/health
* ожидаем JSON со "status": "ok".
Подтянем переменные из .env и проверим доступ к дашборду через basic auth:
source .env
curl -fsS -u '${HERMES_DASHBOARD_BASIC_AUTH_USERNAME}:${HERMES_DASHBOARD_BASIC_AUTH_PASSWORD}' http://127.0.0.1:9119/api/status
Мы должны увидеть что-то на подобие:
{"version":"0.19.1","release_date":"2026.7.30","config_version":33,"latest_config_version":33,"can_update_hermes":false,"gateway_running":true,"gateway_state":"running","gateway_platforms":{"telegram":{"state":"connected","error_code":null,"error_message":null,"updated_at":"2026-08-23T09:46:18.023670+00:00"},"api_server":{"state":"connected","error_code":null,"error_message":null,"updated_at":"2026-08-23T09:46:18.229646+00:00"}},"gateway_exit_reason":null,"gateway_updated_at":"2026-08-23T09:46:18.231547+00:00","active_agents":0,"gateway_busy":false,"gateway_drainable":true,"restart_drain_timeout":0.0,"active_sessions":0,"auth_required":true,"auth_providers":["basic"],"auth_flows":["cookie"],"nous_session_valid":"unknown","components":{"gateway":{"status":"ok","state":"running"},"dashboard":{"status":"ok","recent_unhandled_errors":0,"last_error_at":null,"selftest":"unknown"},"storage":{"status":"ok"},"platforms":{"status":"ok","configured":2,"connected":2}},"overall":"ok","profiles":["default"],"gateway_mode":"single"}
http://192.168.1.20:9119/
* откройте URL в браузере; подставьте IP сервера с Hermes. На странице входа укажите логин и пароль из .env.
Проверим и сам OpenAI-совместимый API — запросим список доступных моделей:
curl -fsS -H "Authorization: Bearer ${API_SERVER_KEY}" http://127.0.0.1:8642/v1/models
Приметный ответ:
{"object": "list", "data": [{"id": "hermes-agent", "object": "model", "created": 1787478889, "owned_by": "hermes", "permission": [], "root": "hermes-agent", "parent": null}]}
Подключаем LLM через ProxyAPI
Получить API ключ и пополнить баланс можно в личном кабинете ProxyAPI. Данный ключ мы должны прописать в файле data/config.yaml (документация, интеграция Hermes):
vi data/.env
PROXYAPI_KEY=ваш-ключ-proxyapi
* ключ ProxyAPI, не OPENAI_API_KEY. Файл лежит в томе data/ (внутри контейнера — ~/.hermes/.env).
Теперь укажем в конфиге агента провайдера и модель по умолчанию:
vi data/config.yaml
* файл уже создан на шаге первичной настройки — добавьте или измените секции ниже, не удаляя остальное.
model:
provider: "custom:proxyapi-anthropic"
default: "claude-sonnet-4-5"
custom_providers:
- name: proxyapi-openai
base_url: https://api.proxyapi.ru/openai/v1
key_env: PROXYAPI_KEY
api_mode: chat_completions
- name: proxyapi-anthropic
base_url: https://api.proxyapi.ru/anthropic
key_env: PROXYAPI_KEY
api_mode: anthropic_messages
- name: proxyapi-openrouter
base_url: https://api.proxyapi.ru/openrouter/v1
key_env: PROXYAPI_KEY
api_mode: chat_completions
- name: proxyapi-gemini
base_url: https://openai.api.proxyapi.ru/v1
key_env: PROXYAPI_KEY
api_mode: chat_completions
* где:
- model.provider / default — провайдер и модель по умолчанию; для Anthropic — имя без префикса anthropic/ (например, claude-sonnet-4-5).
- custom_providers — каталоги ProxyAPI с путями https://api.proxyapi.ru/...; один ключ PROXYAPI_KEY для всех.
- api_mode — для Anthropic нужен anthropic_messages, для OpenAI/OpenRouter/Gemini — chat_completions.
- proxyapi-gemini — универсальный OpenAI-совместимый endpoint; модели в формате gemini/имя-модели.
Применим новые настройки:
docker-compose restart
docker-compose ps
Проверим напрямую, что ProxyAPI принимает запросы с нашим ключом:
source data/.env
curl -fsS https://api.proxyapi.ru/anthropic/v1/messages -H "Content-Type: application/json" -H "Authorization: Bearer ${PROXYAPI_KEY}" -d '{"model":"claude-sonnet-4-5","max_tokens":32,"messages":[{"role":"user","content":"ping"}]}'
* ответ Anthropic API через ProxyAPI подтверждает ключ и endpoint. Альтернатива внутри сессии Hermes: /model custom:proxyapi-openai:gpt-5.5.
Убедимся, что агент действительно использует нужного провайдера и модель:
docker exec -it hermes hermes config get model.provider
docker exec -it hermes hermes config get model.default
* ожидаем custom:proxyapi-anthropic и выбранное имя модели.
Оптимизация затрат
Отдельно настроим сжатие контекста, сброс сессий и лимит шагов агента — это снижает расход токенов на длинных диалогах:
vi data/config.yaml
compression:
enabled: false
...
session_reset:
mode: idle
idle_minutes: 30
...
agent:
max_turns: 150
verbose: false
reasoning_effort: medium
personalities:
helpful: You are a helpful, friendly AI assistant.
concise: You are a concise assistant. Keep responses brief and to the point.
technical: You are a technical expert. Provide detailed, accurate technical information.
creative: You are a creative assistant. Think outside the box and offer innovative
solutions.
teacher: You are a patient teacher. Explain concepts clearly with examples.
# kawaii: You are a kawaii assistant! Use cute expressions like (???), ?, ?, and
# ~! Add sparkles and be super enthusiastic about everything! Every response should
# feel warm and adorable desu~! ?(>∀<?)?
# catgirl: You are Neko-chan, an anime catgirl AI assistant, nya~! Add 'nya' and
# cat-like expressions to your speech. Use kaomoji like (=^?ω?^=) and ?^•?•^?.
# Be playful and curious like a cat, nya~!
# pirate: 'Arrr! Ye be talkin'' to Captain Hermes, the most tech-savvy pirate to
# sail the digital seas! Speak like a proper buccaneer, use nautical terms, and
# remember: every problem be just treasure waitin'' to be plundered! Yo ho ho!'
# shakespeare: Hark! Thou speakest with an assistant most versed in the bardic arts.
# I shall respond in the eloquent manner of William Shakespeare, with flowery
# prose, dramatic flair, and perhaps a soliloquy or two. What light through yonder
# terminal breaks?
# surfer: Duuude! You're chatting with the chillest AI on the web, bro! Everything's
# gonna be totally rad. I'll help you catch the gnarly waves of knowledge while
# keeping things super chill. Cowabunga!
# noir: The rain hammered against the terminal like regrets on a guilty conscience.
# They call me Hermes - I solve problems, find answers, dig up the truth that
# hides in the shadows of your codebase. In this city of silicon and secrets,
# everyone's got something to hide. What's your story, pal?
# uwu: hewwo! i'm your fwiendwy assistant uwu~ i wiww twy my best to hewp you! *nuzzles
# your code* OwO what's this? wet me take a wook! i pwomise to be vewy hewpful
* необязательные персонажи (kawaii, catgirl, pirate и другие) закомментированы по умолчанию — включаются раскомментированием нужных строк.
Перезапустим контейнер, чтобы новые настройки вступили в силу:
docker-compose restart
docker-compose ps
Обновление и остановка агента
Для обновления образа остановим контейнер, скачаем новую версию и запустим заново:
docker-compose down
docker-compose pull
docker-compose up -d
* перед pull смените тег образа в docker-compose.yml на нужный релиз. Данные в data/ при обновлении образа сохраняются.
Проверим версию агента после обновления:
docker exec -it hermes hermes version
Посмотрим лог загрузки контейнера, если после обновления что-то работает не так:
tail -n 100 data/logs/container-boot.log
* лог загрузки контейнера и восстановления gateway-профилей лежит на томе данных.
В каталоге data/ хранятся конфиг, сессии и ключи агента, поэтому перед обновлением или экспериментами стоит сделать резервную копию. Архивируем из каталога /opt/hermes, чтобы пути внутри архива были относительными:
cd /opt/hermes && tar czf hermes-backup-$(date +%F).tar.gz data
* относительный путь при распаковке не тянет за собой абсолютный /opt/hermes/data — архив можно развернуть в любое место без риска перезаписать чужой /opt.
Если что-то пошло не так
Dashboard refuses to bind / no auth providers
Контейнер падает или в логах отказ старта дашборда на 0.0.0.0.
Причина: на non-loopback bind обязателен auth-провайдер, а в .env нет пары username/password (или OAuth client id).
Решение: заполните HERMES_DASHBOARD_BASIC_AUTH_USERNAME, PASSWORD и SECRET в .env, затем docker-compose up -d.
curl /health connection refused
curl http://127.0.0.1:8642/health не отвечает, healthcheck unhealthy.
Причина: API server выключен или еще не поднялся; неверный API_SERVER_HOST.
Решение: в .env должны быть API_SERVER_ENABLED=true и API_SERVER_HOST=0.0.0.0; подождите start_period healthcheck и проверьте docker-compose logs.
Permission denied на /opt/data
В логах ошибки записи в каталог данных.
Причина: права на каталог data/ на хосте не позволяют пользователю внутри контейнера писать файлы.
Решение: выровняйте владельца каталога под UID пользователя hermes в образе (смотрите в документации образа / docker exec hermes id) или временно для диагностики проверьте права ls -la data.
Два контейнера на один data-каталог
Поврежденные сессии, странные ошибки памяти агента.
Причина: два экземпляра Hermes пишут в один bind-mount.
Решение: оставьте один контейнер на каталог data/; для второго профиля используйте отдельный каталог или hermes profile create внутри того же контейнера.
Basic auth в дашборде подходит для доступа из локальной сети или по VPN. Для публикации в интернете нужен OAuth через Nous Portal либо reverse-proxy с TLS перед контейнером — иначе логин и пароль дашборда уходят по сети в открытом виде.