BunkerWeb — открытый обратный прокси на базе NGINX, который из коробки включает ModSecurity с набором правил OWASP Core Rule Set, ограничение частоты запросов, защиту от автоматизированных сканеров, автоматический выпуск сертификатов и интеграцию с CrowdSec. Его смысл в том, чтобы не собирать защитный контур из десятка отдельных модулей, а поставить перед приложением готовый узел, который настраивается переменными окружения. Ниже — установка, подключение сервиса, первичная настройка правил и разбор типичных проблем.
Как устроен BunkerWeb
В основе лежит NGINX, который принимает трафик на портах 80 и 443 и передаёт его приложению. Поверх работают модули: WAF на ModSecurity, антибот, лимиты запросов, проверка репутации адресов, кэширование и балансировка. Конфигурация хранится не в обычных файлах nginx, а в наборе параметров, которые планировщик собирает и рассылает экземплярам. В контейнерной поставке NGINX слушает внутри 8080 и 8443, поэтому наружу пробрасываются именно эти порты, а не 80 и 443 напрямую.
- bunkerweb — сам прокси и WAF, принимает трафик и применяет правила.
- bw-scheduler — хранит настройки, генерирует конфигурацию и перезагружает экземпляры.
- bw-ui — веб-интерфейс с мастером первоначальной настройки и редактором сервисов.
- bw-db — база MariaDB для настроек, пользователей и статистики.
Для небольшой инсталляции есть образ all-in-one: в нём уже собраны прокси, планировщик, интерфейс и SQLite. Он удобен для теста и домашнего стенда, но в продакшене лучше раздельные контейнеры: компоненты обновляются независимо.
Быстрый запуск в Docker
Ниже — ключевая часть compose-файла: прокси и планировщик, а база и интерфейс добавляются отдельными сервисами. Планировщику нужно знать имя экземпляра и диапазон адресов, с которых разрешено обращаться к внутреннему API. Этот диапазон должен совпадать с подсетью служебной сети, иначе планировщик не сможет отправить конфигурацию.
x-bw-env: &bw-env
API_WHITELIST_IP: "127.0.0.0/8 10.20.30.0/24"
DATABASE_URI: "mariadb+pymysql://bunkerweb:changeme@bw-db:3306/db"
services:
bunkerweb:
image: bunkerity/bunkerweb:1.6.17
ports:
- "80:8080/tcp"
- "443:8443/tcp"
- "443:8443/udp"
environment: *bw-env
networks: [bw-universe, bw-services]
bw-scheduler:
image: bunkerity/bunkerweb-scheduler:1.6.17
environment:
<<: *bw-env
BUNKERWEB_INSTANCES: "bunkerweb"
MULTISITE: "yes"
networks: [bw-universe, bw-db]
Пароль к базе из примера обязательно замените на длинный случайный. Сеть bw-universe нужна для обмена конфигурацией, bw-services — для доступа к защищаемым приложениям, bw-db — для базы. Сервис bw-ui слушает порт 7000; публиковать его наружу не стоит — доступ к интерфейсу лучше ограничить файрволом или открывать через SSH-туннель.
Подключение приложения
Сервис описывается теми же параметрами, что и в файле variables.env: имя домена, режим обратного прокси и адрес бэкенда. Для нескольких сайтов включается MULTISITE, а параметры получают префикс с именем домена. Такой префикс — главная причина ошибок: без него настройка применится глобально и переопределит остальные сайты.
MULTISITE=yes
SERVER_NAME=app.example.com
app.example.com_USE_REVERSE_PROXY=yes
app.example.com_REVERSE_PROXY_URL=/
app.example.com_REVERSE_PROXY_HOST=http://app:3000
Контейнер приложения должен находиться в сети bw-services, иначе имя app не разрешится и вы получите 502. После правки конфигурации планировщик перезапускают, чтобы он пересобрал файлы и разослал их экземплярам.
HTTPS и сертификаты
Автоматический выпуск включается параметром AUTO_LETS_ENCRYPT=yes; для проверки домена нужен открытый 80-й порт и корректная A-запись. Если сайт стоит за CDN или балансировщиком, дополнительно настраивают Real IP, иначе в журналах будут адреса промежуточного узла, а лимиты начнут срабатывать для всех клиентов сразу. Проверить цепочку и срок действия проще двумя командами, чем через браузер.
curl -I https://app.example.com
openssl s_client -connect app.example.com:443 -servername app.example.com </dev/null | openssl x509 -noout -dates
Первая команда показывает код ответа и заголовки, вторая — даты выпуска и истечения сертификата.
Что включить в первую очередь
USE_MODSECURITY=yesиUSE_MODSECURITY_CRS=yes— базовый WAF с набором правил.USE_LIMIT_REQ=yesс разумной скоростью, напримерLIMIT_REQ_RATE=20r/s.USE_BAD_BEHAVIOR=yes— временная блокировка клиентов, генерирующих много ошибок.USE_CROWDSEC=yes, если рядом развёрнут CrowdSec с локальными сценариями.LOG_LEVEL=infoна время настройки, затем возврат кnotice.
Начинать с максимального уровня паранойи не стоит: PL1 даёт меньше ложных срабатываний, а повышать его имеет смысл после того, как журнал неделю оставался чистым. Для чувствительных форм и API правила уточняют точечно, а не отключают WAF целиком.
Диагностика: баны и ложные срабатывания
Заблокированный адрес разблокируется утилитой bwcli, которая есть и в контейнере, и в Linux-установке. Перед снятием бана полезно понять причину: в журнале WAF видно идентификатор правила и итоговую оценку аномалии, а не только факт отказа.
docker exec bw-scheduler bwcli unban 203.0.113.10
docker logs --tail 200 bunkerweb | grep -i modsecurity
cat /var/log/bunkerweb/error.log | tail -50
Если правило срабатывает на легитимный запрос, помогает режим обнаружения: он пропускает трафик, но пишет события. После сбора статистики добавляют исключение для конкретного параметра или пути. Отключать правило 949110, которое выносит решение о блокировке, нельзя — это сломает подсчёт аномалий.
Ресурсы, обновление и резервное копирование
Для тестового стенда достаточно двух ядер и восьми гигабайт памяти, для продакшена с десятком сайтов закладывают четыре ядра и шестнадцать гигабайт.
Перед обновлением фиксируют тег образа, а не используют latest. Настройки и статистика лежат в томе bw-data (в compose он получает префикс проекта), конфигурация интерфейса — в bw-ui-data. Копию удобно снимать с остановленного планировщика, иначе дамп базы может оказаться несогласованным.
docker compose stop bw-scheduler
docker run --rm -v bw-data:/src -v "$PWD":/backup alpine tar czf /backup/bw-data.tgz -C /src .
docker compose up -d bw-scheduler
После обновления проверяют docker compose ps, журналы и тестовый запрос к каждому домену. Если новый образ ведёт себя иначе, возврат к прежнему тегу занимает минуту — при условии, что том с данными не мигрировал безвозвратно и совместим со старой версией.
Итог
BunkerWeb закрывает типовые задачи защиты веб-приложения без ручной сборки конфигурации NGINX: WAF, лимиты, HTTPS и веб-интерфейс уже включены. Разумный порядок внедрения — поднять стенд, пропустить через него реальный трафик в режиме обнаружения, настроить исключения и только потом включать блокировки. Тогда защита не превратится в источник отказов для пользователей.