Симптом
Входной сервер не применяет свою конфигурацию, сколько бы её ни редактировали: снаружи порт :443 «ведёт себя чужим», соединение не поднимается. Конфигурация на сервере при этом объективно корректна. Тупик: плумбинг здоров, а трафика нет.
Причина: ядро уводит трафик до сервиса
На сервере остались осколочные правила iptables в таблице nat от прошлой роли «прозрачный форвардер»:
PREROUTING -d <IP-сервера> --dport 443 -j DNAT --to <чужой-сервер>:443
+ MASQUERADE под них
Входящий трафик на порт молча уводится ядром на другой сервер ещё до того, как дойдёт до локального сервиса. Конфигурация локального сервиса полностью исправна — поэтому её правки ни на что не влияют.
Диагностическое золото — расхождение «снаружи ≠ с localhost» на одном порту. Reality/TLS маскируется под конкретный сайт, поэтому сертификат выдаёт подмену:
openssl s_client -connect <IP>:443 -servername <ожидаемый-SNI> </dev/null | openssl x509 -noout -subject
Снаружи возвращается сертификат чужого сервиса — того, куда уводит DNAT. А с самого сервера (-connect 127.0.0.1:443) — правильный: DNAT-правило с привязкой к внешнему интерфейсу не срабатывает для loopback-трафика, отсюда иллюзия «изнутри всё верно».
Решение
- Перед сборкой любого входного или транзитного узла проверять nat-таблицу:
iptables -t nat -S | grep DNAT. Осколочные правила удалить (docker-managed MASQUERADE не трогать). - Сверять сертификат снаружи против localhost. Чужой субъект сертификата на своём порту — перехват на сетевом уровне, а не проблема конфигурации.
- Полная переустановка узла тоже сносит осколки nat, но точечное удаление правил быстрее и безопаснее.
Вывод. Когда «конфигурация правильная, но не работает», подозревайте перехват на слое ниже приложения: ядро (DNAT, redirect, policy-routing) способно молча увести трафик мимо сервиса, и приложение об этом не узнает. Сравнение поведения снаружи и с localhost на одном порту мгновенно вскрывает сетевой перехват, а проверка идентичности по сертификату — быстрый способ поймать подмену назначения.