Когда на сервере появляется Docker, файрвол перестаёт быть «только вашим»: демон сам создаёт и обновляет правила для проброса портов, межконтейнерной связи и маскарадинга. На системах, где по умолчанию используется nftables (а iptables работает через совместимый бэкенд), это часто превращается в путаницу: «правила есть, но не срабатывают», «после перезагрузки всё иначе», «firewalld конфликтует», «контейнеры внезапно доступны извне».
Ниже — практическая схема: чем отличается iptables-legacy от iptables-nft, какие цепочки и правила Docker добавляет в фильтр и NAT, где находится точка контроля (DOCKER-USER), и как не получить «две параллельные реальности» при настройке firewall.
Ключевая идея: Docker управляет правилами, но оставляет вам точку контроля
Docker исторически «заточен» под iptables и ожидает, что сможет:
- создавать свои цепочки (например,
DOCKER,DOCKER-ISOLATION-STAGE-1,DOCKER-ISOLATION-STAGE-2); - встраиваться в стандартные цепочки (
INPUT/FORWARD/OUTPUT, а такжеPREROUTING/POSTROUTINGв NAT); - динамически обновлять правила при старте/остановке контейнеров и публикации портов (
-p 80:80и т.п.).
На современных дистрибутивах обычно встречаются два режима iptables:
- iptables-legacy — классический стек iptables;
- iptables-nft — iptables как «фронтенд», который пишет правила в nftables (объекты nft в семействах
ip/ip6).
Для вас это означает одно: управлять и диагностировать нужно в одной выбранной плоскости. Если система использует iptables-nft, то правки «чистого nft ruleset» поверх того, что меняют Docker и firewalld, быстро превращаются в расследования «почему так, если я всё закрыл».
iptables vs nftables в контексте Docker: что ломается чаще всего
1) «Я настроил nftables, а Docker всё равно открыл порт»
Причина почти всегда в том, что публикация порта контейнера — это не «вход на хост» (INPUT), а связка DNAT+FORWARD:
- DNAT в
nat/PREROUTINGотправляет трафик с порта хоста на IP контейнера; filter/FORWARDрешает, пропустить ли этот трафик дальше в docker-bridge.
Если вы усиливаете только INPUT, а FORWARD оставляете «как получится», порт может стать доступен извне даже при «закрытом» хосте.
2) «Я запретил всё в iptables, но контейнеры всё равно доступны»
Типичный сценарий «двух миров»: вы правите nftables напрямую, а смотрите iptables (или наоборот). Итог — кажется, что «правил нет», хотя они живут в другом месте. Диагностика должна быть консистентной: если у вас iptables-nft, проверяйте и iptables-вывод, и итоговый ruleset nftables.
3) «firewalld и Docker дерутся за FORWARD»
firewalld тоже динамически управляет правилами и цепочками. Конфликт чаще проявляется так:
FORWARDвнезапно становитсяDROPпо умолчанию, и контейнеры теряют сеть;- меняются приоритеты, и jump в docker-цепочки оказывается не там, где вы ожидали.

Если Docker для вас — основа инфраструктуры (reverse proxy, очереди, базы, мониторинг), удобнее держать это на предсказуемом сервере, где вы полностью контролируете ядро и сетевые политики. Для таких задач обычно выбирают VDS с понятной сетевой конфигурацией и доступом к системным настройкам.
Какие цепочки создаёт Docker и где искать точку контроля
С практической точки зрения держите в голове три слоя, где обычно «живёт проблема»:
- Фильтрация транзита (цепочка
FORWARDи дочерние docker-цепочки). - NAT (DNAT на входе и маскарадинг на выходе).
- Пользовательская вставка — цепочка
DOCKER-USER.
DOCKER-USER: зачем она нужна и как её использовать
DOCKER-USER — «официальный» механизм, который Docker оставляет администратору. Docker добавляет прыжок из FORWARD в DOCKER-USER раньше, чем в свои внутренние цепочки. Это позволяет вводить глобальные политики доступа к контейнерам так, чтобы Docker их не перетирал при пересоздании контейнеров и сетей.
Если нужно ограничить доступ к опубликованным контейнерам по IP/подсети/интерфейсу, начинайте с
DOCKER-USER. Это стабильнее, чем редактировать цепочкуDOCKERвручную.
Пример: разрешить доступ к опубликованным портам контейнеров только с одной подсети, а остальное запретить (работает и при iptables-nft):
iptables -N DOCKER-USER
iptables -C FORWARD -j DOCKER-USER 2>/dev/null || iptables -I FORWARD 1 -j DOCKER-USER
iptables -F DOCKER-USER
iptables -A DOCKER-USER -s 203.0.113.0/24 -j RETURN
iptables -A DOCKER-USER -j DROP
Логика тут важнее конкретных значений: RETURN возвращает управление в основной поток docker-правил (то есть «разрешаем продолжить обработку»), а финальный DROP режет всё, что не попало под ваши условия.
Почему нельзя «надежно» править цепочку DOCKER
Цепочка DOCKER и цепочки изоляции bridge-сетей принадлежат Docker. При изменении сетей, публикации портов и перезапуске демона правила будут пересозданы, и ручные правки либо исчезнут, либо окажутся в неправильном порядке.
NAT Docker: как устроен проброс портов и где применяются правила
Когда вы публикуете порт контейнера командой вида docker run -p 80:80 ..., Docker обычно делает две вещи:
- добавляет DNAT в
nat/PREROUTING(и часто вnat/OUTPUTдля локального доступа), чтобы трафик на порт хоста попадал на IP контейнера; - добавляет или обновляет разрешающие правила в
filter/FORWARD, чтобы пакет прошёл транзитом в bridge-сеть.
Дополнительно для исходящего трафика контейнеров «в интернет» включается маскарадинг (обычно MASQUERADE в nat/POSTROUTING), если контейнеры сидят за приватным docker-bridge и наружу выходят через IP хоста.
Отсюда и типовой «провал»: админ усиливает INPUT (всё закрыто), публикует контейнерный порт, и он становится доступен извне через DNAT+FORWARD, хотя на уровне INPUT вы действительно «ничего не открывали».
Если хотите глубже понять, как именно Docker встраивается в цепочки и почему порядок обработки решает, посмотрите материал как Docker взаимодействует с firewall и куда попадает трафик.
Как понять, что у вас: iptables-legacy или iptables-nft
Сначала определите бэкенд iptables:
iptables --version
nft --version
Если в версии iptables есть пометка про nft, значит команды iptables управляют nftables-правилами. Тогда диагностика должна включать и просмотр через iptables, и итоговый ruleset nft:
iptables -S
iptables -t nat -S
nft list ruleset
Практическое правило: не смешивайте «ручной nft ruleset» и «ручной iptables ruleset», пока не договорились сами с собой, кто источник правды. Иначе получите ситуацию, где вы правите одно, а работает другое.
Практические стратегии: как жить с Docker на nftables без сюрпризов
Стратегия A: оставить Docker управление iptables (iptables-nft) и фильтровать через DOCKER-USER
Для одиночного сервера это обычно самый надёжный вариант: Docker пишет свои правила, а вы накладываете политику доступа в DOCKER-USER. Плюсы:
- публикация портов работает «из коробки»;
- межконтейнерная связь не ломается;
- ваши ограничения не перетираются при пересоздании контейнеров.
Стратегия B: отключить управление iptables у Docker и описать правила самостоятельно
Иногда нужен полный контроль: строгие политики ingress/egress, несколько аплинков, нестандартный NAT, собственные таблицы nftables, сложный routing-policy. Тогда можно отключить авто-правила Docker параметром iptables в конфиге демона.
Пример /etc/docker/daemon.json:
{
"iptables": false
}
После этого вам придётся самостоятельно обеспечить:
- форвардинг между интерфейсами (хост ⇄ docker-bridge);
- DNAT для опубликованных сервисов (или отказаться от
-pи публиковать сервисы через reverse proxy на хосте); - маскарадинг для исходящего трафика контейнеров.
Отключайте docker-iptables только если готовы поддерживать сетевую модель руками и понимаете, как ваши docker-сети маршрутизируются на хосте.
firewalld и Docker: как избежать конфликтов и «плавающих» правил
С firewalld обычно две задачи: сохранить предсказуемость и не потерять сеть контейнеров после обновления или перезагрузки. На практике помогают три принципа:
- Не дублировать управление одной плоскостью. Если firewalld управляет nftables, а Docker пишет через iptables-nft, это терпимо. Но если вы ещё и руками правите nft ruleset, становится трудно объяснять приоритеты.
- Проверять политику FORWARD. Если после включения firewalld контейнеры теряют интернет, чаще всего причина именно в
FORWARDи зонах. - Фиксировать вход на контейнеры через DOCKER-USER. Даже с firewalld это удобная точка: вы фильтруете транзит к docker-bridge в одном месте.
Для быстрой диагностики «почему контейнер недоступен снаружи» соберите факты по шагам: опубликован ли порт, куда он DNAT’ится, и проходит ли FORWARD:
docker ps --format '{{.Names}} {{.Ports}}'
iptables -t nat -S | grep -E 'DOCKER|dport'
iptables -S FORWARD
iptables -S DOCKER-USER
nft list ruleset
Если вы раздаёте контейнерные сервисы наружу, не забывайте про TLS: проще и правильнее сразу поставить сертификаты и завершать HTTPS на reverse proxy. Для продакшена удобно держать под рукой SSL-сертификаты, чтобы не оставлять панели и API «на голом HTTP».
Типовые кейсы и решения
Кейс 1: контейнер доступен «всем», хотя нужен доступ только из локальной сети
Не пытайтесь закрыть это через INPUT. Добавьте ограничение в DOCKER-USER по источнику и в конце поставьте DROP. При необходимости дополнительно фильтруйте по входному интерфейсу (например, разрешать только с интерфейса внутренней сети).
Кейс 2: после включения firewalld контейнеры потеряли доступ наружу
Проверьте, что форвардинг разрешён и docker-bridge находится в ожидаемой зоне. Важно понимать: трафик контейнеров чаще проходит через FORWARD, а не через OUTPUT хоста. Поэтому «разрешить исходящие» для хоста не равно «разрешить исходящие для контейнеров».
Кейс 3: вы используете чистый nftables ruleset и хотите предсказуемые правила
Выберите один источник правды. Либо оставьте iptables-nft и управляйте через iptables/DOCKER-USER (и не пишите параллельно свои nat/forward в nft), либо отключите iptables у Docker и полностью опишите NAT/forward в nftables сами. «Смешанный режим», где часть правил вносит Docker, часть — firewalld, часть — ваши nft-скрипты, почти всегда заканчивается ночными расследованиями.

Мини-чеклист: что проверить, если Docker и firewall не дружат
- Бэкенд iptables:
iptables --version. - Прыжок в DOCKER-USER из
FORWARDи его порядок относительно остальных правил. - Правила NAT от Docker: DNAT в
PREROUTING, MASQUERADE вPOSTROUTING. - Не режет ли firewalld forward: смотрите итоговый ruleset, а не только список «разрешённых сервисов».
- IPv6: если включали IPv6 в Docker, отдельно проверяйте
ip6tablesи семействоip6в nftables (часто IPv4 настроен, а IPv6 либо внезапно открыт, либо полностью не работает).
Итог
Связка Docker и iptables исторически понятна и отлажена, но на современных дистрибутивах она всё чаще работает через nftables (iptables-nft). Чтобы вернуть контроль и предсказуемость, держите в голове две вещи: (1) публикация портов — это почти всегда DNAT+FORWARD, а не INPUT; (2) DOCKER-USER — лучший стабильный крючок для ваших ограничений. Дальше выбирайте стратегию: либо доверяете Docker управлять правилами и фильтруете доступ через DOCKER-USER, либо отключаете docker-iptables и берёте NAT/forward полностью на себя.
Если вы хотите усилить изоляцию контейнеров не только сетевыми правилами, но и на уровне песочницы рантайма, посмотрите материал про изоляцию контейнеров с gVisor и Firecracker.


