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

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

MAATRIX

Если вам нужно видеть, что происходит на серверах — кто логинится, какие файлы меняются, есть ли следы компрометации — и при этом не платить за коммерческий SIEM, Wazuh закрывает эту задачу почти полностью бесплатно. Проблема в том, что развернуть его руками долго: три сервиса, сертификаты между ними, куча переменных окружения, которые легко перепутать. Ниже — рабочий docker-compose.yml, который поднимает Wazuh с нуля, и разбор, что в нём происходит и куда чаще всего утыкаются при первом запуске.

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

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

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

Что такое Wazuh и зачем он нужен

Wazuh — это open source платформа класса SIEM/XDR: она собирает логи и события безопасности с серверов, анализирует их по правилам, ищет аномалии и складывает всё в единую консоль с алертами. Изначально Wazuh был форком OSSEC (агент-серверная система обнаружения вторжений на хостах), но за последние годы вокруг него вырос полноценный стек — свой поисковый индекс (форк OpenSearch/Elasticsearch) и веб-дашборд.

Из коробки Wazuh умеет:

  • анализировать логи (syslog, журналы приложений, Windows Event Log) на предмет подозрительных паттернов;
  • мониторить целостность файлов (FIM) — кто и когда изменил конфиг или бинарник;
  • обнаруживать руткиты и аномальное поведение процессов;
  • проверять конфигурацию хостов на соответствие CIS-бенчмаркам (compliance-аудит);
  • собирать инвентарь ПО и уязвимостей по установленным пакетам;
  • реагировать активно — например, банить IP через встроенный active response.

Для одиночного VPS с парой сервисов это, возможно, избыточно — там хватит fail2ban и базового аудита. Но если у вас несколько серверов, инфраструктура растёт, или требуется что-то предъявить аудитору (PCI DSS, ISO 27001, просто внутренняя политика безопасности) — Wazuh даёт централизованную картину по всем хостам сразу.

Архитектура: три сервиса и зачем каждый нужен

Wazuh в контейнерном виде — это не один процесс, а три взаимосвязанных сервиса:

СервисРольПорты
wazuh.indexerхранилище и полнотекстовый поиск по событиям (форк OpenSearch)9200 (внутренний)
wazuh.managerядро: правила, декодеры, приём событий от агентов, API1514/udp, 1515, 55000
wazuh.dashboardвеб-интерфейс поверх индексатора443

Агенты (легковесный демон, который ставится на каждый мониторимый сервер) шлют события на manager по порту 1514, manager обрабатывает их по правилам и пишет результат в indexer, а dashboard визуализирует то, что лежит в индексаторе. Все три сервиса общаются между собой по TLS — отсюда требование сертификатов, о котором ниже.

Важный нюанс: сам indexer (на базе OpenSearch) — самый тяжёлый компонент по памяти. Даже на однохостовой установке "для теста" закладывайте не меньше 4 ГБ RAM под весь стек, а для рабочей нагрузки с несколькими агентами и историей логов — от 8 ГБ. Это ориентир, а не гарантия: конкретное потребление зависит от числа агентов и объёма событий, у вас цифры могут отличаться заметно.

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

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

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

Минимальные требования и подготовка сервера

Перед разворачиванием:

# Docker Engine + Compose plugin (если ещё не стоит)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# OpenSearch (движок индексатора) требует увеличенного vm.max_map_count
sudo sysctl -w vm.max_map_count=262144
echo 'vm.max_map_count=262144' | sudo tee -a /etc/sysctl.conf

Последняя команда критична — без неё indexer падает при старте с ошибкой max virtual memory areas vm.max_map_count is too low. Это самая частая причина, почему "docker compose up" не взлетает с первого раза.

Создайте рабочую директорию и структуру для конфигов и сертификатов:

mkdir -p ~/wazuh-docker/config/wazuh_indexer_ssl_certs
cd ~/wazuh-docker

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

Ниже — минимальная однохостовая конфигурация: все три сервиса на одном сервере, с самоподписанными сертификатами и персистентными volume для данных.

services:
  wazuh.manager:
    image: wazuh/wazuh-manager:4.9.2
    hostname: wazuh.manager
    restart: always
    ports:
      - "1514:1514"
      - "1515:1515"
      - "514:514/udp"
      - "55000:55000"
    environment:
      - INDEXER_URL=https://wazuh.indexer:9200
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=${INDEXER_PASSWORD}
      - FILEBEAT_SSL_VERIFICATION_MODE=full
      - SSL_CERTIFICATE_AUTHORITIES=/etc/ssl/root-ca.pem
      - SSL_CERTIFICATE=/etc/ssl/filebeat.pem
      - SSL_KEY=/etc/ssl/filebeat.key
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=${API_PASSWORD}
    volumes:
      - wazuh_api_configuration:/var/ossec/api/configuration
      - wazuh_etc:/var/ossec/etc
      - wazuh_logs:/var/ossec/logs
      - wazuh_queue:/var/ossec/queue
      - ./config/wazuh_indexer_ssl_certs/root-ca-manager.pem:/etc/ssl/root-ca.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.manager.pem:/etc/ssl/filebeat.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.manager-key.pem:/etc/ssl/filebeat.key
    networks:
      - wazuh-net
    depends_on:
      - wazuh.indexer

  wazuh.indexer:
    image: wazuh/wazuh-indexer:4.9.2
    hostname: wazuh.indexer
    restart: always
    ports:
      - "9200:9200"
    environment:
      - "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - wazuh-indexer-data:/var/lib/wazuh-indexer
      - ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-indexer/certs/root-ca.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.indexer-key.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.key
      - ./config/wazuh_indexer_ssl_certs/wazuh.indexer.pem:/usr/share/wazuh-indexer/certs/wazuh.indexer.pem
      - ./config/wazuh_indexer_ssl_certs/admin.pem:/usr/share/wazuh-indexer/certs/admin.pem
      - ./config/wazuh_indexer_ssl_certs/admin-key.pem:/usr/share/wazuh-indexer/certs/admin-key.pem
    networks:
      - wazuh-net

  wazuh.dashboard:
    image: wazuh/wazuh-dashboard:4.9.2
    hostname: wazuh.dashboard
    restart: always
    ports:
      - "443:5601"
    environment:
      - INDEXER_USERNAME=admin
      - INDEXER_PASSWORD=${INDEXER_PASSWORD}
      - WAZUH_API_URL=https://wazuh.manager
      - DASHBOARD_USERNAME=kibanaserver
      - DASHBOARD_PASSWORD=${DASHBOARD_PASSWORD}
      - API_USERNAME=wazuh-wui
      - API_PASSWORD=${API_PASSWORD}
    volumes:
      - ./config/wazuh_indexer_ssl_certs/wazuh.dashboard.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard.pem
      - ./config/wazuh_indexer_ssl_certs/wazuh.dashboard-key.pem:/usr/share/wazuh-dashboard/certs/wazuh-dashboard-key.pem
      - ./config/wazuh_indexer_ssl_certs/root-ca.pem:/usr/share/wazuh-dashboard/certs/root-ca.pem
      - wazuh-dashboard-config:/usr/share/wazuh-dashboard/data/wazuh/config
      - wazuh-dashboard-custom:/usr/share/wazuh-dashboard/plugins/wazuh/public/assets/custom
    networks:
      - wazuh-net
    depends_on:
      - wazuh.indexer

networks:
  wazuh-net:
    driver: bridge

volumes:
  wazuh_api_configuration:
  wazuh_etc:
  wazuh_logs:
  wazuh_queue:
  wazuh-indexer-data:
  wazuh-dashboard-config:
  wazuh-dashboard-custom:

Пароли вынесены в .env рядом с compose-файлом:

cat > .env <<'EOF'
INDEXER_PASSWORD=ЗамениНаСложныйПароль1
API_PASSWORD=ЗамениНаСложныйПароль2
DASHBOARD_PASSWORD=ЗамениНаСложныйПароль3
EOF
chmod 600 .env

Версии образов (4.9.2 в примере) стоит сверить с актуальным релизом на Docker Hub Wazuh на момент установки — проект выпускает обновления регулярно, и слепо тянуть старый тег означает пропустить фиксы безопасности.

Генерация сертификатов и первый запуск

Три сервиса общаются по TLS, и без сертификатов indexer откажется стартовать. Официальный путь — утилита wazuh-certs-generator, которая работает через отдельный конфиг:

cat > config.yml <<'EOF'
nodes:
  indexer:
    - name: wazuh.indexer
      ip: wazuh.indexer
  server:
    - name: wazuh.manager
      ip: wazuh.manager
  dashboard:
    - name: wazuh.dashboard
      ip: wazuh.dashboard
EOF

docker run --rm -ti \
  -v "$(pwd)/config.yml:/config/config.yml" \
  -v "$(pwd)/config/wazuh_indexer_ssl_certs/:/certificates/" \
  wazuh/wazuh-certs-generator:0.0.2

Эта команда создаёт корневой CA и по сертификату на каждый узел прямо в config/wazuh_indexer_ssl_certs/, куда их и подключает compose-файл выше. Дальше — обычный запуск:

docker compose up -d
docker compose logs -f wazuh.indexer   # дождитесь "started" перед следующим шагом

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

curl -k -u admin:${INDEXER_PASSWORD} https://localhost:9200/_cluster/health?pretty

Дашборд открывается по https://ваш_ip/ (порт 443), логин по умолчанию admin с паролем из .env. Сертификат самоподписанный — браузер предупредит, это ожидаемо; для продакшена стоит поставить обратный прокси с Let's Encrypt перед dashboard или сразу настроить свой SSL-терминатор.

Подключение агентов для мониторинга

Wazuh без агентов — это просто пустая консоль. Агент ставится на каждый сервер, за которым нужно наблюдать, и указывает на manager. На Ubuntu/Debian:

curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --dearmor -o /usr/share/keyrings/wazuh.gpg
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" | \
  tee /etc/apt/sources.list.d/wazuh.list
apt update && WAZUH_MANAGER='адрес_вашего_manager' apt install -y wazuh-agent
systemctl enable --now wazuh-agent

Проверить, что агент появился в manager: docker exec -it <container_wazuh.manager> /var/ossec/bin/agent_control -l.

Регистрация по умолчанию идёт через автоматическую авторизацию на порту 1515 — для продакшена лучше включить проверку по паролю (authd.pass в конфиге manager) или ограничить порт 1515 firewall'ом до момента регистрации, чтобы посторонний хост не смог примазаться к вашей группе агентов.

Если у вас уже есть VPN между серверами — например, разворачивали стек VPN в Docker Compose — логично слать трафик агент-manager через него, а не через открытый интернет, тогда порт 1514 наружу вообще не публикуется.

Настройка правил и алертов под задачу

Из коробки Wazuh уже включает сотни правил (SSH-брутфорс, изменение системных файлов, попытки эскалации привилегий и т.д.), но полезность SIEM определяется тем, насколько правила подогнаны под вашу инфраструктуру. Базовые шаги:

  • Файловый мониторинг (FIM). В /var/ossec/etc/ossec.conf на агенте укажите директории для отслеживания: <syscheck><directories check_all="yes" realtime="yes">/etc,/usr/bin,/usr/sbin,/var/www/html</directories></syscheck>.
  • Свои правила. Кастомные декодеры и правила кладутся в /var/ossec/etc/rules/local_rules.xml на manager (том wazuh_etc в compose-файле) — например, правило на подозрительный User-Agent в логах nginx или на серию неудачных попыток входа в вашу CMS.
  • Active response. Можно настроить автоматическую реакцию — например, бан IP через iptables при срабатывании правила брутфорса, аналогично тому, как это делает fail2ban, но с централизованным управлением со всех серверов сразу.
  • Compliance-модули. Для CIS-бенчмарков и PCI DSS/HIPAA-отчётов включите соответствующие wodles в конфиге manager — они периодически прогоняют проверки конфигурации на агентах и складывают результат в те же дашборды.

Если Wazuh стоит не ради галочки, а для реального compliance-аудита с логами VPN-подключений, посмотрите отдельный разбор интеграции VPN и SIEM для комплаенса — там про то, какие именно события VPN-сервера стоит заворачивать в SIEM и зачем.

Типичные проблемы и что делать

  • Indexer не стартует, в логах vm.max_map_count is too low. Забыли sysctl -w vm.max_map_count=262144 на хосте — контейнер не может выставить этот параметр сам.
  • Manager не достучаться до indexer, SSL handshake failed. Почти всегда рассинхрон сертификатов: имена в config.yml при генерации должны буква в букву совпадать с hostname: сервисов в compose-файле.
  • Dashboard висит на экране ожидания индексатора. Обычно индексатор ещё не поднялся полностью, либо пароли в .env не совпадают с тем, что прописано в internal_users.yml — сверьте оба файла при первом запуске.
  • Агент не появляется в списке на manager. Проверьте, что порты 1515 (регистрация) и 1514 (события) реально открыты между хостами в firewall, а не только опубликованы в compose.
  • Indexer съедает память сервера. OPENSEARCH_JAVA_OPTS в примере жёстко держит heap на 1 ГБ — для рабочей нагрузки увеличивайте вместе с общим RAM, ориентируясь на docker stats, а не на цифры по умолчанию.
  • После docker compose down пропали события. Проверьте, что не запускали с флагом -v — он удаляет именованные volumes вместе с данными.

Если в целом Wazuh кажется избыточным для вашего масштаба, а нужен просто централизованный сбор и разбор логов без правил безопасности — присмотритесь к более лёгким вариантам вроде Grafana Loki или почитайте про ротацию логов, если задача — просто не забить диск.

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

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

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

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

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

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

Сколько ресурсов реально нужно на одном сервере?

Для теста с 1-3 агентами хватит 4 ГБ RAM и 2 vCPU. Для продакшена с десятком агентов и хранением истории от 30 дней закладывайте от 8 ГБ RAM и SSD-диск — indexer активно пишет и читает с диска, на HDD производительность просядет заметно.

Можно ли развернуть indexer, manager и dashboard на разных серверах?

Да, это рекомендованная схема для нагруженных инсталляций — тот же compose-файл разбивается на три отдельных, сервисы общаются по внутренней сети или VPN, а не по localhost. Файл в этой статье — однохостовый вариант для старта.

Wazuh правда бесплатный?

Ядро платформы (агент, manager, indexer, dashboard) — open source под GPLv2, без ограничений по числу агентов. Компания Wazuh Inc. продаёт коммерческую поддержку и облачный SaaS-вариант, но self-hosted версия из этой статьи полностью бесплатна в использовании.

Чем Wazuh отличается от связки Grafana + Prometheus?

Это разные классы инструментов: Grafana с Prometheus — про метрики производительности (CPU, память, latency), Wazuh — про события безопасности (кто зашёл, что изменилось, есть ли атака). Их часто ставят рядом, а не вместо друг друга.

Нужен ли отдельный сервер под Wazuh или можно на том же, где крутится сайт?

Технически можно, но не рекомендуется: indexer нагружает диск и память, а сам сервер, за которым наблюдают, логичнее держать отдельно от системы наблюдения — иначе при компрометации сайта под угрозой окажется и сама SIEM.

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

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

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