MAATRIX / Блог / Huginn на сервере: частые ошибки и решения

Huginn на сервере: частые ошибки и решения

MAATRIX

Huginn — открытая агентная система на Ruby on Rails: вы описываете правила («следи за этой страницей», «дергай этот API раз в час», «шли уведомление, если появилось новое») и она выполняет их сама, без облачных подписок. Но именно из-за того, что это классический Rails-монолит с фоновыми джобами, а не легкий Go-бинарник, при разворачивании на своем сервере вылезает целая пачка специфичных проблем — от отказа стартовать без APP_SECRET_TOKEN до агентов, которые «висят», но ничего не делают. Ниже — конкретные причины и решения, которые реально встречаются в проде.

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

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

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

Huginn не стартует: APP_SECRET_TOKEN и переменные окружения

Самая частая причина падения контейнера на первом же старте — незаданный APP_SECRET_TOKEN. Rails генерирует его сам только при rails new, а в готовом docker-образе Huginn эту переменную обязаны передать вы, иначе процесс упадет с ошибкой вида Missing secret_key_base или просто зациклится в рестарте.

Сгенерировать токен и сразу прописать его в compose-файл:

openssl rand -hex 64

Минимальный рабочий docker-compose.yml для Huginn с PostgreSQL:

services:
  huginn:
    image: huginn/huginn:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      APP_SECRET_TOKEN: "вставьте_сюда_hex_из_openssl"
      DATABASE_ADAPTER: postgresql
      DATABASE_HOST: postgres
      DATABASE_NAME: huginn
      DATABASE_USERNAME: huginn
      DATABASE_PASSWORD: "надежный_пароль"
      DOMAIN: agents.example.com
      FORCE_SSL: "true"
      SMTP_DOMAIN: example.com
    depends_on:
      - postgres
    volumes:
      - huginn_data:/var/lib/huginn

  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_DB: huginn
      POSTGRES_USER: huginn
      POSTGRES_PASSWORD: "надежный_пароль"
    volumes:
      - pg_data:/var/lib/postgresql/data

volumes:
  huginn_data:
  pg_data:

Проверить, что переменная реально попала внутрь контейнера:

docker compose exec huginn env | grep APP_SECRET_TOKEN

Если строка пустая — Docker не подхватил .env-файл или compose перезапущен без пересборки переменных. Полезная общая база по граблям compose в проде — Docker Compose для продакшена: частые ошибки и решения.

Ошибки подключения к базе данных

Huginn хранит агентов, события и логи в PostgreSQL (или MySQL — оба поддерживаются). Классическая ошибка при первом запуске:

PG::ConnectionBad: could not connect to server: Connection refused

Причина почти всегда одна: контейнер приложения стартует раньше, чем Postgres успел поднять сокет и принять соединения — depends_on в Docker Compose гарантирует только порядок запуска контейнеров, а не готовность сервиса внутри. Решение — health-check на базе и condition: service_healthy:

postgres:
  image: postgres:16
  healthcheck:
    test: ["CMD-SHELL", "pg_isready -U huginn"]
    interval: 5s
    timeout: 5s
    retries: 10

huginn:
  depends_on:
    postgres:
      condition: service_healthy

Про то, как правильно настраивать проверки готовности контейнеров в целом — в статье Docker healthcheck: настройка.

Вторая по частоте ошибка — PG::UndefinedTable после первого старта: миграции не применились автоматически. Запустите их вручную:

docker compose exec huginn bundle exec rake db:migrate

Если база лежит не в соседнем контейнере, а на отдельном сервере (что разумно для нагруженной инсталляции), проверьте, что Postgres слушает внешние подключения (listen_addresses = '*' в postgresql.conf) и что в pg_hba.conf есть строка для IP-адреса вашего Huginn-сервера — иначе получите no pg_hba.conf entry for host.

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

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

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

Агенты не срабатывают по расписанию

Это самая коварная проблема: интерфейс открывается, агенты созданы, всё выглядит нормально — но события не появляются. У Huginn есть отдельный фоновый процесс-планировщик (bin/schedule.rb в исходной установке, встроен в entrypoint у docker-образа), который должен работать постоянно, параллельно с веб-сервером. Если контейнер настроен только на веб-процесс, планировщик не запускается вообще.

Проверьте логи именно на упоминание scheduler:

docker compose logs huginn | grep -i schedule

Официальный образ huginn/huginn запускает планировщик автоматически внутри одного контейнера через supervisord — но если вы используете вариант с разделением на huginn-web и huginn-schedule (рекомендуется для нагруженных инсталляций), убедитесь, что второй сервис реально в compose и не упал:

huginn-web:
  image: huginn/huginn:latest
  command: foreman start -m web
  environment:
    RAILS_ENV: production
    <<: *common-env

huginn-schedule:
  image: huginn/huginn:latest
  command: foreman start -m schedule
  environment:
    RAILS_ENV: production
    <<: *common-env

Отдельно проверьте таймзону — многие агенты (например, на основе расписания cron-строки в поле Schedule) считают время по таймзоне контейнера, а не по вашей. Если сервер живет в UTC, а вы ждете срабатывания «в 9 утра по Москве», агент отработает в 6 утра UTC — то есть как задумано, но не тогда, когда вы ожидаете. Разница между системным cron и внутренним планировщиком приложения разобрана в Cron-задачи на сервере: частые ошибки и решения — логика применима и к Huginn.

Если планировщик работает, но конкретный агент не срабатывает — проверьте поле «Disabled» в его настройках и вкладку Logs самого агента (не общий лог контейнера): там видно последнюю попытку запуска и ошибку, если она была.

Не хватает памяти: OOM-килы и подвисания

Huginn — это Rails-приложение плюс PostgreSQL плюс фоновые воркеры, и на слабых VPS (1 ГБ RAM и меньше) это частая причина падений: ядро Linux убивает процесс через OOM killer, а в логах Docker вы видите просто exit code 137 без внятной причины внутри самого приложения.

Проверить, было ли это OOM:

dmesg | grep -i "killed process"
docker inspect <container_id> | grep -i OOMKilled

Если OOMKilled: true — дело именно в памяти. Ориентировочно для стабильной работы Huginn с несколькими десятками активных агентов и Postgres на той же машине закладывайте от 2 ГБ RAM; на 1 ГБ приложение будет запускаться, но начнет падать под нагрузкой (это ориентир, а не измеренное значение — точная цифра зависит от числа агентов и объема обрабатываемых событий). Логика подбора памяти для похожих Rails/Node-агентных систем разобрана в Сколько RAM нужно для n8n — цифры для Huginn обычно в том же порядке, но не идентичны, потому что стек другой.

Быстрый и безопасный способ пережить пики без немедленного апгрейда тарифа — добавить swap:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Swap не заменяет нормальную RAM (диск на порядки медленнее), но превращает жесткий краш в просадку производительности — для фонового агентного сервиса это обычно приемлемый компромисс, пока вы не увеличите тариф.

Webhook-агенты не получают входящие запросы

Huginn умеет принимать вебхуки (Post Agent на прием, Webhook Agent) — это ключевая фича для интеграций с внешними сервисами. Если внешний сервис жалуется на таймаут или 502 при попытке достучаться до вашего вебхука, проблема почти всегда в reverse proxy перед контейнером, а не в самом Huginn.

Типичная ошибка в конфиге nginx — не увеличен таймаут и не проброшен правильный Host:

server {
    listen 443 ssl http2;
    server_name agents.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 90s;
        proxy_send_timeout 90s;
    }
}

Без X-Forwarded-Proto Huginn (при включенном FORCE_SSL) может уходить в бесконечный редирект — внешний сервис видит 301, идет по нему, снова получает 301, и в итоге просто обрывает соединение по своему таймауту. Если используете Traefik вместо nginx, логика та же — важно прокинуть заголовки и не забыть про сертификат: смотрите Traefik как reverse proxy для докера.

Проверить, доходит ли запрос до контейнера вообще, минуя внешние сервисы:

curl -X POST http://127.0.0.1:3000/users/1/web_requests/<agent_id>/<secret> -d "test=1"

Если локально ответ приходит, а снаружи — нет, дело в файрволе или DNS, а не в Huginn: проверьте ufw status и что A-запись домена реально указывает на IP вашего сервера.

Почта не отправляется: SMTP и Email Agent

Huginn использует email как один из основных каналов уведомлений (Email Agent, DigestAgent с отправкой на почту), и без настроенного SMTP эта функциональность просто молча не работает — в логах будет Net::SMTPAuthenticationError или Connection refused на порт 25/587.

Рабочий блок переменных для отправки через внешний SMTP (например, свой почтовый сервер или транзакционный сервис):

environment:
  SMTP_DOMAIN: example.com
  SMTP_SERVER: smtp.example.com
  SMTP_PORT: 587
  SMTP_USER_NAME: bot@example.com
  SMTP_PASSWORD: "пароль_приложения"
  SMTP_AUTHENTICATION: plain
  SMTP_ENABLE_STARTTLS_AUTO: "true"
  EMAIL_FROM_ADDRESS: bot@example.com

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

docker compose exec huginn nc -zv smtp.example.com 587

Если порт 587 (или 465 с SSL) открыт, а 25 заблокирован — просто используйте 587 со STARTTLS, для внешних SMTP-провайдеров это стандартная и более надежная схема в любом случае.

Диск заполняется: логи и старые события

Huginn по умолчанию хранит все сработавшие события в базе бессрочно, и на активной инсталляции с десятками агентов, дергающих API каждые несколько минут, таблица events в Postgres может разрастись до гигабайтов за месяцы работы — а вместе с ней и место на диске.

Проверить размер таблицы:

SELECT pg_size_pretty(pg_total_relation_size('events'));

У каждого агента в настройках есть keep_events_for (в днях) — выставьте разумное значение вместо бессрочного хранения, если вам не нужна полная история:

{
  "keep_events_for": 604800
}

(значение в секундах — здесь это 7 дней). После изменения настройки Huginn чистит старые события внутренним cleanup-джобом не мгновенно — при большом накопленном объеме имеет смысл прогнать VACUUM FULL на таблице events вручную в окно низкой нагрузки, эта команда блокирует таблицу на время работы.

Отдельно проверяйте логи самого Docker — при restart: unless-stopped и падающем каждые несколько минут контейнере (например, из-за незамеченного OOM) логи драйвера json-file без ограничения размера способны съесть весь диск за пару недель:

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

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

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

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

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

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

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

Huginn поддерживает MySQL вместо PostgreSQL?

Да, оба адаптера официально поддерживаются — переключается переменной DATABASE_ADAPTER: mysql2 и соответствующими DATABASE_*. PostgreSQL немного лучше документирован в сообществе и используется чаще, поэтому проще искать решения по нему.

Можно ли запустить несколько независимых Huginn на одном сервере?

Да, через разные порты и отдельные volumes/базы в одном docker-compose или через отдельные compose-проекты — но с учетом требований к памяти каждой инсталляции, суммарный расход RAM растет линейно.

Как обновить Huginn без потери агентов?

Обновите образ (docker compose pull), пересоздайте контейнер (docker compose up -d) — база данных на отдельном volume сохраняется, а миграции применятся автоматически при старте официального образа. Перед обновлением на проде сделайте дамп базы: docker compose exec postgres pg_dump -U huginn huginn > backup.sql.

Huginn зависает при обработке большого JSON-ответа от API — что делать?

Обычно это не зависание, а долгий парсинг Liquid-шаблонов в JavaScript/EventFormattingAgent на больших массивах — проверьте вкладку Logs агента на предмет таймаута и по возможности фильтруйте данные раньше, на уровне запроса, а не после получения.

Нужен ли Huginn отдельный Redis?

Нет, базовая установка обходится без Redis — вся очередь задач и кэш живут в PostgreSQL через delayed_job. Redis не требуется, если вы не подключаете сторонние расширения, которые явно его просят.

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

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

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