Внешний файрвол для Docker
ℹ️ Возможность доступна начиная с версии MikoPBX 2026.2.76. На более ранних версиях LAPI-эндпоинт
firewall-bouncer, баннер на странице файрвола и кнопка «Токен для bouncer» отсутствуют.
Проблема
В Docker-режиме MikoPBX внутренние правила файрвола и fail2ban не защищают веб-интерфейс:
Контейнер не управляет iptables хоста.
При
userland-proxy=true(поведение Docker по умолчанию) контейнер видит HTTP-клиента какdocker0-шлюз (например172.17.0.1), а не как реальный IP атакующего. ACL уровня Nginx и fail2ban-jail для веб-формы блокируют только этот шлюз — то есть никого.
SIP-защита при этом работает: UDP-DNAT сохраняет source IP, Asterisk видит реальный адрес, fail2ban пишет блокировку в Redis и module reload acl отбивает дальнейшие REGISTER. Сломан именно HTTP-сегмент.
Решение — экспортировать решения о блокировке наружу и применять их в настоящем файрволе хоста (или edge-CDN, или security-group облака) при помощи внешнего обработчика правил.
Шаг 1. Проверьте, ваш ли это случай
На странице Безопасность → Доступ к веб-интерфейсу есть жёлтый баннер «Docker bridge: требуется внешний обработчик правил». Если он показан — этот документ для вас.

Кнопка Проверить видимость моего IP запросит эндпоинт system:checkClientIpVisibility и покажет три значения:
ip_visible— реальный IP клиента виден, ничего не требуется.ip_not_visible— IP клиента подменён на шлюз Docker bridge: правила HTTP-файрвола работать не будут.proxy_detected— перед АТС стоит reverse-proxy, и АТС намеренно не доверяет proxy-заголовкам. Настройте прокси на отображение реального IP или разверните внешний bouncer.
Шаг 2. Выберите подход
Вариант A — network_mode: host (минимум усилий)
network_mode: host (минимум усилий)Если хост — выделенный сервер для АТС и нет конфликтов портов, переключите контейнер в host-режим:
В этом режиме контейнер использует сетевой namespace хоста, Asterisk и Nginx видят реальные source-IP, а внутренний файрвол работает «как на bare metal». Подходит лучше всего для SIP-нагруженных инсталляций.
Ограничения: один host-режим на хост, нельзя поднять рядом несколько копий АТС, конфликты с другими процессами на стандартных портах.
Вариант B — cs-firewall-bouncer apt-пакетом на хосте
cs-firewall-bouncer apt-пакетом на хостеКонтейнер MikoPBX остаётся в bridge-режиме. На Linux-хосте ставится cs-firewall-bouncer (open-source, проект CrowdSec), который поллит эндпоинт MikoPBX каждые 10 секунд и переносит решения в iptables/nftables хоста.
Это рекомендуемый вариант для большинства инсталляций.
1. Создайте API-токен
Откройте Система → API-ключи.
Нажмите кнопку Токен для bouncer (предзаполняет правильное ограничение пути).
Откроется форма создания ключа. Описание («Внешний firewall bouncer (CrowdSec-совместимый)») и API-ключ уже подставлены — при необходимости выберите Сетевой фильтр, чтобы ограничить source-IP, с которого можно опрашивать эндпоинт. Тумблер «Полные права доступа» оставьте выключенным: кнопка Токен для bouncer уже выставила нужное ограничение пути
/api/v3/firewall-bouncer.

Сохраните. Откроется модальное окно с готовой конфигурацией
cs-firewall-bouncer.yaml— скопируйте её сразу, API-ключ показывается только один раз.

2. Установите bouncer на хосте
3. Настройте
Откройте /etc/crowdsec/bouncers/cs-firewall-bouncer.yaml и замените api_url / api_key на значения из шага 1:
📌
api_url— это базовый URL. cs-firewall-bouncer сам дописывает/v1/decisions/streamи отправляет токен в заголовкеX-Api-Key. Не указывайте полный путь кdecisions/streamвapi_urlи не добавляйте префиксBearerк ключу — bouncer всё делает сам.
⚠️ Если ваш MikoPBX слушает HTTPS с self-signed сертификатом, добавьте
insecure_skip_verify: trueили установите CA-сертификат на хост.
🚨
iptables_chains: [INPUT, FORWARD, DOCKER-USER]— это не дефолт CrowdSec (по умолчанию там толькоINPUT). БезDOCKER-USERтрафик, который Docker маршрутизирует в контейнер, идёт через цепочкуDOCKERи не доходит до DROP-правила bouncer'а — бан виден в iptables, но в реальности не работает. Это самая частая ловушка при подключении CrowdSec к Docker-развёрнутой АТС.
4. Проверьте
В логах bouncer должно появиться
received N new decisions, 0 deleted.sudo iptables -L CROWDSEC -n(илиcrowdsec-firewall-bouncer-iptables-v6для IPv6) покажет добавленные блокировки.Заблокируйте тестовый IP вручную через раздел Файрвол → Сети или спровоцируйте fail2ban-блокировку и убедитесь, что строка появилась в iptables хоста в течение 30 секунд.
Замечания по production-развёртыванию
Защита SSH (и других админ-портов) от bouncer'а
Bouncer'ы CrowdSec блокируют на уровне IP, а не протокола — одна запись в ipset дропает все TCP- и UDP-пакеты с забаненного адреса. В том числе порт 22. Если IP оператора по ошибке попадёт в бан-лист (скажем, fail2ban зафиксировал три неудачных auth:login с NAT-IP офиса), то SSH тоже отрежется, и админ запрётся снаружи хоста.
Вставьте высокоприоритетный ACCEPT для админ-порта до DROP-правила bouncer'а, чтобы административный доступ оставался жив даже если IP самого оператора попадёт в бан:
Повторите для любых других портов, через которые вы администрируете машину (Wireguard, serial-консоль провайдера и т.д.) — для всего, что не должно падать под bouncer'а.
Опционально: safety-net на systemd-timer
Для инсталляций, где потеря доступа к хосту дорого стоит, добавьте systemd-timer, периодически чистящий ipset bouncer'а. Bouncer перезальёт текущие баны на следующем poll'е, так что это безопасный safety-net с ограниченным blast radius, а не отключение функции:
30 минут — разумный дефолт: короче, чем время остывания кофе оператора, если он случайно себя забанит, и длинее, чем нужно реальной атаке, чтобы заметно ущербнуть.
Bouncer-баны покрывают все протоколы — by design
CrowdSec мапит решения в один ipset на IP-семейство. Правила iptables дропают весь трафик с перечисленных IP, независимо от протокола и порта. Бан mikopbx/http (HTTP-брутфорс) автоматически отрезает тому же IP и SIP / IAX / AMI / SSH — и наоборот: бан mikopbx/sip (fail2ban-jail Asterisk) тоже дропнет HTTP и AMI от того же IP. MikoPBX отдаёт в bouncer-стрим все четыре категории банов (sip, http, ami, iax) одинаково, так что после подключения bouncer'а любая блокировка становится IP-wide.
Для большинства инсталляций это правильное поведение — если IP агрессивен к HTTP, в SIP его пускать тоже незачем, и наоборот. Но если нужно по-протокольное разделение (например, блокировать HTTP-брутфорсеров, не трогая их SIP), bouncer для этой АТС поднимать не нужно. Существующий путь защиты SIP внутри Docker'а (fail2ban → Redis → pjsip ACL внутри Asterisk) изолирует SIP-баны именно потому, что они не уходят в host ipset — а bouncer ровно это поведение и меняет.
Формат ответа эндпоинта
GET /pbxcore/api/v3/firewall-bouncer/v1/decisions/stream возвращает снимок текущих решений в виде, который ожидает стоковый cs-firewall-bouncer — {new, deleted} на верхнем уровне, без обёртки MikoPBX:
Массив new[] всегда содержит полный снимок текущих банов — bouncer обновляет таймауты своих ipset/nftables-записей до значения duration на каждом poll'е, поэтому активный бан живёт ровно столько, сколько указал источник. Массив deleted[] считается per-token (MikoPBX хранит прошлый снимок по id'у ApiKey) и содержит решения, которые исчезли с предыдущего опроса. Снятие бана оператором доходит до ipset bouncer'а за один poll-цикл (≈ 5–10 секунд), а не ждёт естественного истечения TTL.
?startup=true на первом poll'е после рестарта bouncer'а сбрасывает per-token cursor и возвращает deleted: [] — свежезапущенный bouncer не получит фантомных удалений для состояния, которое он никогда не отслеживал.
Оба варианта заголовков аутентифицируют один и тот же токен:
Сосуществующий эндпоинт whitelist (кастомный)
GET /pbxcore/api/v3/firewall-bouncer/v1/whitelist возвращает whitelist оператора как плоский JSON-массив:
Этот эндпоинт — специфика MikoPBX. Стоковый cs-firewall-bouncer его не опрашивает (в CrowdSec LAPI нет типа решения «allow», bouncer ведёт собственный whitelists.yaml). Предоставлен для MikoPBX-aware интеграций, которым нужна согласованность whitelist с NetworkFilters АТС на стороне сервера.
Технические подробности
Детальный формат, query-параметры и сопоставление категорий MikoPBX с полями CrowdSec описаны в разделе Эндпоинт firewall-export.
Last updated
Was this helpful?

