После 6+ лет в инфраструктуре я решил нормально разобраться с автономными AI-агентами. Не с чат-ботами, которые красиво отвечают в окно, а с системами, которые умеют планировать работу, запускать команды, читать код и трогать инфраструктуру.
Для кого этот разбор#
Эта статья не про «поставил чат-бота и поигрался». Hermes Agent интересен тогда, когда агент получает реальные инструменты: терминал, файлы, GitHub, браузер, память, интеграции и право что-то менять.
Поэтому основной вопрос инфраструктурный: как дать агенту достаточно возможностей для работы и не превратить его в неконтролируемый root-скрипт с красивым интерфейсом.
Когда наткнулся на Hermes Agent от Nous Research, решил поднять его у себя на сервере и проверить без демо-режима: поможет ли он с текстами, рутиной, инфраструктурными задачами и долгими исследованиями.
Спойлер: получилось полезнее, чем ожидал. Базовая установка заняла около четырёх часов, а самые важные выводы появились не в промптах, а в инфраструктурных мелочах.
Что у меня было на старте#
Сервер на обычной виртуалке — 4 GB RAM, 60 GB SSD, Ubuntu 22.04. Ничего особенного. Есть домен для внешних сервисов через Selectel DNS. Docker, Caddy, базовые навыки администрирования — стандартный набор.
Опыт с AI? Работаю с Cursor для pet-проектов, экспериментировал с ML/AI инструментами в разработке. Но концепция автономных агентов, способных выполнять цепочки действий без участия разработчика, заинтересовала как новый подход к автоматизации.
Цель была простая: поднять агента, которым реально можно пользоваться — с Telegram, русским языком, отдельными профилями, контролем расходов и нормальной обвязкой вокруг сервера.
Подготовка сервера#
Первым делом настроил чистую виртуалку под задачу. Отдельный SSH-ключ для безопасности, смена стандартного порта 22 на нестандартный — базовые меры предосторожности.
Установка Hermes прошла через официальный скрипт:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
Скрипт сам настроил Python-окружение, поставил зависимости и создал команду запуска. После установки запустил мастер настройки:
hermes setup
Мастер настройки оказался нормальным: по шагам провёл через выбор модели, провайдера (я выбрал OpenRouter за гибкость) и базовые инструменты. На этом этапе все основные компоненты уже работали через CLI.
Но мне нужен был доступ через Telegram и веб-интерфейс. Тут началось интересное.
Первые грабли: веб-панель и настройка доступа#
По умолчанию веб-панель слушает только localhost:9119. Для внешнего доступа нужно было прокинуть через reverse proxy. Я привык к Caddy, поэтому решил использовать его.
Первая попытка — обычная docker-сеть:
# docker-compose.yml
services:
caddy:
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
networks:
- hermes-net
И сразу же проблема: веб-панель Hermes выдаёт «Invalid Host header» при обращении через прокси. Оказалось, что в коде есть защита от DNS rebinding атак — проверяется заголовок Host.
Проблему решил примерно за 20 минут. Нужно было прокидывать правильный заголовок:
your-domain.com {
reverse_proxy 127.0.0.1:9119 {
header_up Host {upstream_hostport}
}
}
Но это работает только если Caddy может обратиться к 127.0.0.1:9119 на хосте. С docker-сетями это не так просто. Проще всего оказалось использовать network_mode: host: Caddy работает прямо в сетевом пространстве хоста и без проблем достучится до веб-панели.
Да, изоляции меньше, но для собственного сервера это нормальный компромисс. Главное — правильно настроить firewall.
Безопасность: UFW + базовая аутентификация#
С самого начала хотел сделать всё безопасно. Веб-панель — опасная штука: через неё можно выполнять команды на сервере. Оставлять такое без защиты — самоубийство.
UFW настроил по минимуму:
- SSH на нестандартном порту для безопасности
- 80/tcp и 443/tcp для веба
- 443/udp для HTTP/3
- Всё остальное — запрещено по умолчанию
Веб-панель Hermes слушает 0.0.0.0:9119, но порт закрыт снаружи. Доступ только через Caddy с TLS.
Для аутентификации выбрал базовый пароль поверх HTTPS. Для первого запуска этого достаточно, OAuth можно прикрутить позже. В конфиге Hermes:
auth_required: true
auth_password: "сложный_пароль_который_нигде_не_светится"
Дополнительно в Caddyfile настроил IP whitelist — только с определённых адресов можно вообще достучаться до сервиса:
@allowed_ips remote_ip 1.2.3.4 5.6.7.8
abort @denied
Telegram Gateway и первые команды#
Настройка Telegram-бота — отдельная история. В документации всё выглядело просто, но на практике тоже были каверзные моменты.
Создал бота через @BotFather, получил токен. Дальше началось интересное: часть настройки шла уже через сам Hermes в Telegram-чате. Агент сам себя настраивал, понимая команды типа "настрой webhook" или "добавь мой токен".
Проблема оказалась в том, что webhook URL должен быть доступен извне по HTTPS. Мой Caddy уже был настроен с Let's Encrypt, но URL указывал на localhost. Поправил конфиг:
telegram:
webhook_url: https://your-domain.com/webhook/telegram
bot_token: "токен_от_BotFather"
После этого бот ожил и начал отвечать. После первой проверки стало понятно, что это не игрушка: агент отвечает на русском, держит контекст и может выполнять команды.
Но хотелось большего — чтобы он мог работать с веб-страницами, анализировать документы, создавать собственную базу знаний.
Firecrawl: локальный web scraper#
Hermes умеет работать с веб-страницами через различные сервисы. Firecrawl показался наиболее подходящим — open source, можно развернуть локально, не зависит от внешних API.
Клонировал репозиторий Firecrawl, настроил через docker-compose. В базовой конфигурации всё работает, но есть засада — потребление памяти.
По умолчанию Firecrawl запускает 8 worker'ов, каждый жрёт 200-300 MB RAM. На моём сервере с 4 GB это критично — остаётся слишком мало места для других сервисов.
Пришлось урезать лимиты:
NUM_WORKERS_PER_QUEUE=3
CRAWL_CONCURRENT_REQUESTS=4
MAX_CONCURRENT_JOBS=2
BROWSER_POOL_SIZE=2
После этого потребление упало до разумных 800 MB, и система перестала давить остальные сервисы.
В конфиге Hermes указал локальный адрес:
web:
firecrawl_api_url: http://127.0.0.1:3002
После этого агент смог читать веб-страницы, вытаскивать из них структурированный текст и использовать это в исследованиях.
gbrain: централизованная память для агентов#
gbrain оказался самой интересной частью настройки. Это общая база знаний для агентов: можно сохранять факты, искать по ним и связывать страницы между собой.
От PGLite к Postgres и HTTP MCP#
Установка через Bun:
curl -fsSL https://bun.sh/install | bash
bun install -g github:garrytan/gbrain
gbrain init
Первый вариант был максимально простой: локальная PGLite-база и gbrain serve как stdio MCP-сервер. Для проверки гипотезы этого хватило, но быстро стало понятно, что файловая локальная база плохо подходит под несколько клиентов: Hermes на сервере, Cursor на ноутбуке, отдельные профили, будущие агенты.
Поэтому gbrain переехал на Postgres и стал отдельным HTTP MCP-сервисом:
gbrain serve --http --port 3131 --bind 127.0.0.1
Сейчас это не одноразовый процесс внутри сессии Hermes, а systemd-сервис gbrain-http.service с Postgres-бэкендом. Hermes подключается к нему по HTTP MCP на localhost:
mcp_servers:
gbrain:
url: http://127.0.0.1:3131/mcp
headers:
Authorization: Bearer ${MCP_GBRAIN_API_KEY}
enabled: true
Важная деталь: это legacy bearer token, не OAuth client credentials. Токен для клиента создаётся командой:
gbrain auth create hermes-gateway
Команда показывает секрет один раз, дальше хранит только хэш. Список токенов можно проверить без раскрытия секрета:
gbrain auth list
Второй клиент к той же базе: Cursor на ноутбуке#
После перехода на HTTP MCP появилась нормальная схема для другого компьютера: наружу публикуется не Postgres, а адрес gbrain MCP через Caddy.
Для отдельного клиента создаётся свой токен:
gbrain auth create cursor-laptop
В Cursor (Settings → MCP → Add new MCP server) добавляется:
{
"mcpServers": {
"gbrain": {
"url": "https://gbrain.your-domain.com/mcp",
"headers": {
"Authorization": "Bearer <токен_из_auth_create>"
}
}
}
}
Это важнее, чем звучит. Раньше я думал в сторону внешнего Postgres: открыть порт, TLS, пароль, sslmode=verify-full. Но после появления MCP-адреса gbrain прямой доступ к базе стал не нужен. Postgres остался внутренней базой gbrain, а все клиенты ходят в один HTTP MCP-слой.
Итог: записи, которые Hermes сохранил с сервера, видны Cursor на ноутбуке. Контекст, который нашёл один агент, доступен другому. Не через копипасту и не через export/import, а через одну общую Postgres-базу за gbrain.
Копирайтер-агент на русском языке#
Для текстов я сделал отдельный профиль Hermes — copywriter. У него свой конфиг, свои навыки и своя модель.
Скопировал базовый профиль:
hermes profile create copywriter --from default
Создал отдельный SOUL.md — файл с ролью и правилами агента:
You are Krolbot's copywriter — a focused Russian-language writing agent.
Your job: write, edit, and review Russian-language marketing copy,
blog posts, and site content for zaitsv.dev / webzaytsev projects.
## Always load on start
- `ru-text` — baseline Russian typography, grammar, info-style
- `krolbot-copywriter-voice` — project-specific voice override
Установил два навыка:
ru-text— базовые правила русской типографики и стиляkrolbot-copywriter-voice— специфичный голос для моих проектов
Позже переключил копирайтера на x-ai/grok-4.20 через OpenRouter. Для русскоязычного текста он оказался полезен именно живым тоном: нормально держит разговорный русский, не пугается мата там, где он уместен, и не превращает инженерный текст в стерильный корпоративный пресс-релиз.
Теперь я могу запустить копирайтера командой:
copywriter chat -q "Напиши пост про новую фичу"
Он работает отдельно от основного агента, подхватывает правила русской типографики и пишет в нужном голосе.
Telegram: Rich Messages оставил, streaming выключил#
С Telegram была отдельная серия граблей. Потоковая генерация выглядела красиво: агент пишет длинный ответ постепенно, и ты видишь прогресс почти сразу.
На практике связка streaming.enabled=true и частых rich Markdown-правок в группе начала упираться в Telegram flood control. Симптом неприятный: одно и то же сообщение могло прилететь дважды — сначала форматированное, потом plain text fallback. В логах это выглядело примерно так:
MarkdownV2 edit failed, falling back to plain text: Flood control exceeded
Telegram flood control, waiting 32-39s
sendRichMessage transient failure
Первый фикс был мягкий: отключить промежуточные сообщения и оставить потоковую генерацию. Это снизило шум, но не убрало проблему полностью. Финальный стабильный вариант такой:
streaming:
enabled: false
display:
streaming: false
interim_assistant_messages: false
tool_progress: new
Rich Messages при этом выключать не пришлось. Таблицы, код-блоки, списки и нормальное Telegram-форматирование остались. Просто агент больше не пытается постоянно править одно и то же сообщение, пока генерирует ответ.
Отдельный вывод: Telegram — не терминал. То, что удобно в CLI, в групповом чате может только мешать. Для длинных ответов лучше меньше постоянных правок и больше аккуратных финальных сообщений.
Практические находки и подводные камни#
За месяц использования накопилось много полезных наблюдений:
Память и ресурсы#
- 4 GB RAM хватает, но только если ограничить Firecrawl workers и не запускать всё подряд без лимитов
- Docker с
network_mode: hostпроще настроить, чем возиться с bridge-сетями - Следите за лимитами worker'ов — они могут съесть всю память
Безопасность#
- Базовой аутентификации через HTTPS достаточно для собственного сервера
- IP allowlist в reverse proxy — дополнительная защита
- UFW с deny по умолчанию — обязательно
- Нестандартный SSH порт — от скриптовых атак
Экономия#
- отдельный профиль
copywriterна Grok 4.20 разгружает основной агент и лучше подходит для живого русского текста - Локальный Firecrawl вместо cloud API — бесплатно
- Отдельные профили для разных задач — не переплачиваете за лишние возможности
Проблемы PATH в systemd#
- для stdio MCP нужен полный путь (
~/.bun/bin/gbrain), потому что systemd не наследует PATH из пользовательской сессии - для gbrain удобнее уйти от stdio к отдельному HTTP MCP-сервису на localhost
- bearer-токены лучше заводить отдельно на каждого клиента, а не шарить один общий секрет
Обновления#
- Docker bind-mount одного файла не подхватывает изменения после редактирования
- После правки Caddyfile иногда нужен
docker compose down && up, не только reload - Hermes gateway нужно перезапускать после изменения MCP-конфигов или env
- после подключения/изменения MCP в живом Telegram-чате помогает
/reload_mcp, но это не заменяет рестарт gateway, если поменялись env/config
Что получилось в итоге#
Сейчас у меня работает нормальная AI-инфраструктура:
- Веб-панель — интерфейс с базовой аутентификацией
- Telegram-бот без потоковой генерации, но с нормальным rich-форматированием и прогрессом по инструментам
- Firecrawl для анализа веб-страниц (локальный, без внешних зависимостей)
- gbrain как HTTP MCP-сервис поверх Postgres: один brain для Hermes, Cursor и других клиентов
- Копирайтер-агент на Grok 4.20 с русской типографикой и проектным стилем
- Безопасная обвязка — firewall, TLS, локальные bind'ы и наружу только нужные MCP/HTTP-адреса
Всё это стабильно работает на обычной 4-гигабайтной виртуалке, но не само по себе: пришлось ограничить Firecrawl, вынести gbrain в отдельный HTTP-сервис, отключить потоковую генерацию в Telegram и перестать открывать наружу то, что должно жить за MCP-слоем.
Стоит ли овчинка выделки?#
Да, если у вас есть задачи, где агент действительно снимает рутину, а не ограничивается красивыми ответами.
За месяц агент помог мне:
- Написать несколько технических статей
- Проанализировать документацию сторонних сервисов
- Автоматизировать рутинные DevOps задачи
- Исследовать новые технологии и подготовить сводки
Базовая настройка заняла примерно четыре часа днём: установка, Telegram, веб-панель, reverse proxy, Firecrawl, gbrain и первые профили. Дальше агент начал окупаться уже в первый месяц использования — на статьях, исследовании документации и автоматизации рутины.
Главное — не пытаться собрать всё за один присест. Сначала базовая установка, потом Telegram, потом Firecrawl, потом память и отдельные профили. И обязательно документируйте свои настройки — пригодится при обновлениях или переносе на другой сервер.
Если вы хотите поставить Hermes Agent для себя или команды, лучше сразу думать не только об установке, но и о границах доступа, памяти, профилях, интеграциях и проверке результата. Напишите мне в Telegram или на почту — помогу спроектировать такой контур без лишней магии и опасных упрощений.



