Запуск 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.

Что понадобится перед установкой

  • 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 перед контейнером — иначе логин и пароль дашборда уходят по сети в открытом виде.

Похожие инструкции

# DevOps # Linux # ИИ # Контейнеризация # Серверы
Дмитрий Моск — частный мастер
Был ли вам полезен этот скрипт?

Да            Нет

Дмитрий Моск
— IT-специалист.
Настройка серверов, услуги DevOps.

Заказать настройку контейнеризации

Нужна бесплатная консультация?

Скрипты

Hermes Agent в Docker Compose: gateway и dashboard

Пример docker-compose для развертывания тестовой SMS-лаборатории

PostgreSQL StatefulSet в Kubernetes на одном хосте

GitLab CE в Docker Compose за Traefik с HTTPS

Пример манифеста для запуска Swagger в Kubernetes

Пример скрипта для миграции запущенной виртуальной машины Proxmox с ZFS репликацией

Пример манифеста для развертывания Hermes AI в Kubernetes

Другие скрипты

Все статьи

Нужен скрипт? Опишите его назначение:





Реклама