🌐 Задача-ловушка: Пропавший трафик после настройки iptables

Условие:

На сервере настроен простой iptables-фильтр для блокировки всего входящего трафика, кроме SSH:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

После применения этих правил вы проверяете, что SSH соединения работают нормально (локально и удалённо). Сервер отвечает на пинги, всё ок.

На следующий день вы добавляете локальный контейнер (например, Docker), запускаете его с пробросом порта:

docker run -d -p 8080:80 nginx

❗️ Проблема: Снаружи контейнер не доступен. В браузере или curl получаете Connection refused. Но в ss -tlnp порт 8080 виден и слушает.

Дополнительно, если выполнить:

curl http://localhost:8080

— сервер отвечает нормально. Но с других машин — нет.

❓ Вопрос:
Почему порт 8080 недоступен извне? В чём подвох с iptables? Как починить проблему?

🔍 Подсказка:

Docker использует nat таблицы и PREROUTING`/`FORWARD цепочки для проброса портов.


✅ Разбор:

💥 Ловушка:

Ваш iptables-правила:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

запрещают ВСЁ, кроме SSH. Вы думаете, что входящие соединения через Docker должны идти через INPUT, но это не так!

Когда Docker пробрасывает порт с хоста (например, 8080), схема такая:

- Входящий пакет попадает в цепочку PREROUTING (nat)
- Потом через FORWARD, если пакет не адресован хосту напрямую, а перенаправлен внутрь контейнера

И тут главная ловушка: даже если контейнер слушает порт на 0.0.0.0, Docker обрабатывает проброс трафика через FORWARD, а у вас политика по умолчанию:

iptables -P FORWARD DROP

Поэтому трафик до контейнера блокируется именно на этапе FORWARD.

🔧 Как проверить:

Запустить:

iptables -L -v -n

Вы увидите, что счётчик пакетов в FORWARD показывает дропы.

🛠 Как починить:

Добавить правило разрешения проброса пакетов для Docker:

iptables -A FORWARD -o docker0 -j ACCEPT

Или (более строго):

iptables -A FORWARD -i eth0 -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT

✅ Вывод:

• В Linux iptables цепочки работают по строгой логике:
- INPUT — для пакетов к хосту
- FORWARD — для пакетов, которые переходят через хост (например, контейнеры или маршрутизаторы)

• Даже если кажется, что контейнер слушает на 0.0.0.0, проброс портов Docker работает через FORWARD, а не напрямую через INPUT.

💡 Бонус-вопрос:
Что изменится, если вы запустите контейнер с флагом --network=host? Какие цепочки будут задействованы тогда?




iptables
Добавлено: Вчера, 22:58
0
6

Похожие публикации



Наверх