MAATRIX / Блог / Huginn в Docker Compose: готовый файл

Huginn в Docker Compose: готовый файл

MAATRIX

Если вы хоть раз писали cron-скрипт «раз в час проверить страницу и прислать в Telegram, если изменилась цена» — вы уже наполовину изобрели Huginn. Разница в том, что Huginn делает это готовыми блоками-агентами, которые можно соединять между собой прямо в браузере, без единой строчки Ruby или Python. Ниже — рабочий docker-compose.yml, который поднимает Huginn с PostgreSQL и почтой за одну команду, плюс нюансы, на которых обычно спотыкаются при первом запуске.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Huginn и зачем он вам

Huginn — это self-hosted платформа для агентов, каждый из которых умеет делать что-то одно: следить за RSS-лентой, дёргать HTTP API по расписанию, парсить страницу по CSS-селектору, слушать вебхук, отправлять сообщение в Telegram или на почту. Агенты соединяются в цепочки — вывод одного становится входом другого, — и получается что-то вроде IFTTT или n8n, но заточенное именно под мониторинг и реакцию на события, а не под сложные бизнес-процессы.

Типичные сценарии, ради которых разворачивают Huginn на своём сервере:

  • следить за ценой товара на маркетплейсе и слать уведомление при снижении;
  • парсить страницу вакансий или тендеров и класть новые записи в таблицу;
  • агрегировать несколько RSS-лент в одну дайджест-рассылку раз в день;
  • дёргать API погоды, курса валют или статуса сервиса и реагировать на аномалии;
  • принимать вебхуки от других систем и пересылать их дальше с трансформацией.

Если задачи сложнее — там нужны ветвления, обращения к базам данных, вызовы LLM — присмотритесь к n8n: он моложе, активнее развивается и умеет заметно больше. Но для узкой задачи «следить и реагировать» Huginn проще в голове и легче для сервера.

Почему не облако, а свой сервер

Официального облачного Huginn как сервиса нет — проект живёт как open-source и разворачивается либо руками, либо через Docker. Это де-факто означает self-hosting: либо у вас дома на Raspberry Pi, либо на VPS. Домашний вариант отпадает быстро, если агенты должны работать круглосуточно и дёргать внешние API из «белого» IP, а не из-за NAT провайдера — многие сервисы банят или капчуют запросы с динамических жилых адресов.

Для стабильной работы агентов, которые опрашивают сайты каждые несколько минут, нужен сервер с постоянным внешним IP, без блокировок по подпискам на VPN-трафик и с адекватным аптаймом. Это ровно тот случай, где годится небольшой VPS — Huginn не требователен к ресурсам, для десятка-двух агентов достаточно 1-2 vCPU и 2 ГБ RAM, с запасом под PostgreSQL. Если план мониторинга разрастётся до сотен агентов с частым опросом — берите конфигурацию с 4 ГБ RAM, чтобы Sidekiq-воркеры не упирались в память.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Готовый docker-compose.yml

Huginn официально поддерживает несколько образов, но самый удобный для одиночного сервера — huginn/huginn (all-in-one, где веб, планировщик и воркеры работают в одном контейнере). Для отдельной БД используем PostgreSQL — с ней Huginn работает надёжнее, чем с MySQL, особенно на больших объёмах событий.

Создайте директорию и файл:

mkdir -p ~/huginn && cd ~/huginn
mkdir -p pg-data huginn-data
nano docker-compose.yml

Содержимое docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    container_name: huginn-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: huginn
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: huginn
    volumes:
      - ./pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U huginn"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - huginn-net

  huginn:
    image: huginn/huginn:latest
    container_name: huginn
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      DATABASE_ADAPTER: postgresql
      DATABASE_NAME: huginn
      DATABASE_USERNAME: huginn
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_HOST: postgres
      DATABASE_PORT: 5432
      APP_SECRET_TOKEN: ${APP_SECRET_TOKEN}
      DOMAIN: ${DOMAIN}
      RAILS_ENV: production
      TIMEZONE: Europe/Moscow
      HUGINN_INVITATION_CODE: ${INVITATION_CODE}
      HUGINN_SEED_USERNAME: admin
      HUGINN_SEED_PASSWORD: ${ADMIN_PASSWORD}
      HUGINN_SEED_EMAIL: ${ADMIN_EMAIL}
      SMTP_DOMAIN: ${DOMAIN}
      SMTP_SERVER: ${SMTP_SERVER:-}
      SMTP_PORT: ${SMTP_PORT:-587}
      SMTP_USER_NAME: ${SMTP_USER:-}
      SMTP_PASSWORD: ${SMTP_PASSWORD:-}
      SMTP_AUTHENTICATION: plain
      SMTP_ENABLE_STARTTLS_AUTO: "true"
      EMAIL_FROM_ADDRESS: ${ADMIN_EMAIL}
    volumes:
      - ./huginn-data:/var/lib/huginn
    ports:
      - "127.0.0.1:3000:3000"
    networks:
      - huginn-net

networks:
  huginn-net:
    driver: bridge

Файл .env рядом с ним:

POSTGRES_PASSWORD=замените-на-длинный-случайный-пароль
APP_SECRET_TOKEN=замените-на-строку-64-hex-символа
DOMAIN=huginn.your-domain.ru
INVITATION_CODE=замените-на-свой-код-приглашения
ADMIN_PASSWORD=замените-на-надёжный-пароль
ADMIN_EMAIL=you@your-domain.ru
SMTP_SERVER=
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=

APP_SECRET_TOKEN сгенерируйте так, чтобы не гадать:

openssl rand -hex 64

Обратите внимание: порт 3000 привязан только к 127.0.0.1 — наружу Huginn отдаётся через reverse proxy с HTTPS, напрямую в интернет Rails-приложение лучше не выставлять.

Запуск и первичная настройка

docker compose up -d
docker compose logs -f huginn

Первый старт займёт минуту-две — контейнер прогоняет миграции базы и сидирует администратора из переменных HUGINN_SEED_*. Когда в логах появится строка про запущенный сервер (обычно puma слушает 3000-й порт), можно логиниться под admin и паролем из .env.

Если вы не задали HUGINN_SEED_* заранее, зайти в контейнер и создать пользователя вручную можно так:

docker compose exec huginn bundle exec rails runner "
User.create!(
  username: 'admin',
  email: 'you@your-domain.ru',
  password: 'надёжный-пароль',
  password_confirmation: 'надёжный-пароль'
).save
"

После первого входа сразу смените пароль через UI и отключите публичную регистрацию (Invitation Code оставьте только для себя — она нужна, чтобы посторонний не завёл аккаунт, если панель случайно окажется доступна извне).

HTTPS через reverse proxy

Проще всего поставить Caddy — он сам получит сертификат Let's Encrypt. Добавьте контейнер в тот же docker-compose.yml или разверните Caddy отдельно на хосте:

huginn.your-domain.ru {
    reverse_proxy 127.0.0.1:3000
}

Если у вас уже есть Traefik для других сервисов на этом сервере — смотрите как настроить Traefik как reverse proxy для Docker, логика та же: лейблы на контейнере вместо отдельного Caddyfile.

Не забудьте открыть 80/443 в файрволе и убедиться, что A-запись домена смотрит на IP вашего сервера, иначе выпуск сертификата зависнет с ошибкой валидации.

Первые агенты: RSS и Website Agent

Логика Huginn — «Agent» (источник или обработчик события) и «Event» (само событие, JSON-объект), которые передаются по цепочке через связи Receiver → Source.

Пример: слежение за изменением цены на странице товара.

  1. Website Agent — опрашивает URL по расписанию, вытаскивает данные CSS/XPath-селектором, создаёт событие только при изменении.
  2. Trigger Agent — сравнивает значение с условием (например, цена ниже порога) и пропускает событие дальше только если условие выполнено.
  3. Telegram Agent или Email Digest Agent — отправляет уведомление.

Минимальный конфиг Website Agent в JSON-виде (вставляется в поле Options при создании агента):

{
  "url": "https://example.com/product/123",
  "type": "html",
  "mode": "on_change",
  "extract": {
    "price": {
      "css": ".price-current",
      "value": "text"
    }
  }
}

Расписание задаётся отдельным полем при создании агента (Schedule) — например, «every_30m» для проверки раз в полчаса. Слишком частый опрос одного и того же сайта — плохая идея не только с точки зрения нагрузки на их сервер, но и с точки зрения бана вашего IP: для внешних сайтов разумный минимум — 15-30 минут между проверками, если явно не указано иное в их robots.txt или API-лимитах.

Для Telegram-уведомлений понадобится Telegram Agent с токеном бота и chat_id — если бота ещё нет, инструкция как поднять Telegram-бота на Python на VPS поможет получить токен через BotFather, дальше он используется просто как канал доставки.

Бэкапы: что и как сохранять

Всё состояние Huginn — в PostgreSQL плюс небольшая директория с загруженными файлами (/var/lib/huginn). Бэкапить нужно оба.

Дамп базы по крону:

#!/bin/bash
# /root/huginn-backup.sh
STAMP=$(date +%Y%m%d-%H%M)
docker compose -f /root/huginn/docker-compose.yml exec -T postgres \
  pg_dump -U huginn huginn | gzip > /root/backups/huginn-$STAMP.sql.gz
find /root/backups -name "huginn-*.sql.gz" -mtime +14 -delete

Добавьте в crontab:

0 3 * * * /root/huginn-backup.sh

Про типичные грабли с cron-заданиями на сервере (неправильный PATH, отсутствие прав на директорию бэкапов, тихие ошибки без логов) — отдельная статья: cron-задачи на сервере: частые ошибки и решения. Тот же принцип полностью применим и к бэкап-скрипту Huginn.

Восстановление из дампа:

gunzip < /root/backups/huginn-20260815-0300.sql.gz | \
  docker compose exec -T postgres psql -U huginn huginn

Директорию huginn-data (вложения, экспортированные файлы агентов) достаточно копировать rsync-ом раз в сутки на отдельный диск или в облачное хранилище — по объёму она обычно небольшая, если вы не храните в Huginn тяжёлые файлы намеренно.

Обновление и обслуживание

Huginn развивается медленнее, чем n8n, но обновления всё равно стоит применять — особенно security-патчи Rails, на котором построен проект. Процесс простой:

cd ~/huginn
docker compose pull huginn
docker compose up -d huginn
docker compose logs -f huginn

Перед серьёзным обновлением (смена мажорной версии образа) — сначала снимите дамп базы, потом обновляйтесь: миграции применяются автоматически при старте контейнера, но откатить их проще с бэкапом под рукой, чем без него.

Если хотите, чтобы образ обновлялся сам, можно повесить Watchtower — но для системы, которая держит критичные для бизнеса уведомления, аккуратнее обновлять вручную и проверять логи после каждого раза, чем полагаться на автообновление среди ночи.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Чем Huginn принципиально отличается от n8n?

Huginn заточен под мониторинг и события: следить, сравнивать, уведомлять. n8n — универсальный движок автоматизации с сотнями интеграций, ветвлениями и поддержкой вызовов LLM. Если задача — «отследи и сообщи», Huginn проще и легче для сервера; если нужен сложный workflow с несколькими системами — берите n8n.

Можно ли использовать MySQL вместо PostgreSQL?

Да, Huginn поддерживает оба адаптера через переменные DATABASE_ADAPTER. PostgreSQL в целом ведёт себя стабильнее под нагрузкой множества параллельных агентов, поэтому в готовом конфиге выбран он.

Сколько агентов потянет минимальный VPS на 2 ГБ RAM?

На практике десяток-два агентов с опросом раз в 15-30 минут работают комфортно. Если агентов становится больше полусотни или опрос частый (каждую минуту), лучше сразу закладывать 4 ГБ RAM — Sidekiq-воркеры и PostgreSQL начинают конкурировать за память.

Huginn поддерживает вебхуки на приём, а не только опрос?

Да, есть Webhook Agent — он создаёт уникальный URL, на который можно слать POST-запросы из внешних систем (например, из формы на сайте или из другого сервиса), и Huginn превращает их в события для дальнейшей обработки.

Что если сайт, за которым я слежу, меняет вёрстку и CSS-селектор ломается?

Website Agent просто перестанет находить нужный элемент и не будет создавать события — без явной ошибки в интерфейсе. Стоит периодически (раз в месяц-два) вручную проверять критичные агенты через «Dry Run» в UI, особенно если сайт-источник обновляет дизайн.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →