Docker и сервер

Docker обходит UFW: закрываем порты через DOCKER-USER

ports: 8080:8080 открывает порт всему интернету мимо firewall. Правильные правила в цепочке DOCKER-USER и два более чистых варианта.

7 мин чтения

Проблема: порт открыт всему интернету, хотя UFW «закрыт»

docker run -p 8080:8080 или ports: ["8080:8080"] в compose открывает порт всему интернету, даже если в UFW нет разрешающего правила. Так служебные сервисы — экспортёры метрик, админки, внутренние API — регулярно торчат наружу, хотя админ уверен, что firewall их закрывает.

Почему UFW не срабатывает: Docker создаёт правила в цепочке DOCKER (NAT + filter), которая обрабатывается до пользовательских цепочек UFW. Пакет попадает в контейнер раньше, чем доходит до правил ufw-before-input:

PREROUTING → DOCKER (filter) → ACCEPT → контейнер
            ↑ UFW сюда вообще не попадает

Проверить снаружи (с другого хоста): timeout 3 bash -c "</dev/tcp/<адрес>/8080" && echo OPEN.

Фикс: цепочка DOCKER-USER

Docker оставляет пустую цепочку DOCKER-USER, которая обрабатывается до его собственных авто-правил. Туда добавляем allow для нужных источников и DROP остального:

iptables-save > /root/iptables-before.txt   # снапшот

iptables -I DOCKER-USER 1 -s <доверенный-IP> -p tcp -m multiport --dports 8080,9090 -j ACCEPT
iptables -I DOCKER-USER 2 -s 127.0.0.1       -p tcp -m multiport --dports 8080,9090 -j ACCEPT
iptables -I DOCKER-USER 3 -s 172.16.0.0/12   -p tcp -m multiport --dports 8080,9090 -j ACCEPT
iptables -A DOCKER-USER  -p tcp -m multiport --dports 8080,9090 -j DROP

apt-get install -y iptables-persistent
iptables-save > /etc/iptables/rules.v4       # пережить reboot

Проверка: снаружи порт таймаутит (DROP), изнутри docker-сети работает. Счётчики iptables -L DOCKER-USER -n -v рассказывают правду: ACCEPT растёт при легитимных обращениях, DROP — при сканах.

Более чистые альтернативы, если готовы пересоздать контейнеры:

Подводные камни

Вывод. Публикация порта в Docker обходит UFW: цепочка DOCKER идёт раньше его правил. Правильное место для ограничений — DOCKER-USER (allow нужных источников, DROP остального) с сохранением через iptables-persistent. Для network_mode: host эта цепочка не действует. А идеально — вообще не публиковать служебные сервисы наружу, связывая их с потребителями по внутренней docker-сети.

Как подключиться за 2 минуты
Частые вопросы

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

Почему опубликованный Docker-порт доступен снаружи при закрытом UFW?
Docker создаёт свои правила в цепочке DOCKER (NAT и filter), которая обрабатывается раньше пользовательских цепочек UFW, поэтому пакет попадает в контейнер, так и не дойдя до правил UFW.
Как проверить снаружи, действительно ли порт открыт всему интернету?
С другого хоста попробовать TCP-подключение к порту (bash-проверка через /dev/tcp с таймаутом): если порт отвечает — он доступен извне независимо от настроек UFW.
Где правильно ограничивать доступ к портам контейнеров?
В цепочке DOCKER-USER: она обрабатывается до авто-правил Docker. Туда добавляют ACCEPT для доверенных источников (включая loopback и docker-подсети) и DROP для всего остального.
Работает ли ограничение через DOCKER-USER для network_mode: host?
Нет — эта цепочка действует только для форвардящегося трафика контейнеров на docker-bridge. Для network_mode: host применяются обычные правила INPUT и UFW.
Есть ли способ вообще не публиковать служебный порт наружу?
Да: биндить порт на loopback (127.0.0.1:8080:8080) с доступом через ssh-туннель или VPN, либо объединить сервисы в одну docker-сеть и обращаться к ним по имени контейнера.
Похожее

Ещё в базе знаний

Подключите рабочий VPN

Инструкции базы знаний написаны под ключи VPN PRO: ключ выдаёт Telegram-бот за минуту, работоспособность гарантируем. Промокод VPN10 — 10 дней бесплатно, без карты.

Промокод VPN10 — 10 дней бесплатно · до 31 августа · передавайте друзьям