Ваш сервис работает на машине, туннель поднят, а браузер на вашем столе всё ещё не получает ответа. В обычном смысле ничего не сломано: приложение слушает внутри сетевого пространства имён, и этот стек невидим для LAN. Его loopback принадлежит пространству имён, поэтому у клиента на другой машине нет адреса, который доходит до порта. Один намеренный прыжок или одна пара veth исправляет это, не перемещая остальную часть хоста.

Почему на адресе LAN никто не отвечает

Пространство имён — это полный сетевой стек: интерфейсы, маршруты, правила межсетевого экрана и приватный loopback. Процесс, запущенный через ip netns exec, видит только этот стек и ничего больше, поэтому адрес, к которому он привязывается, разрешается только внутри пространства имён. Собственный 127.0.0.1 хоста — это совсем другой loopback.

Поэтому curl на хосте терпит неудачу, а та же команда внутри пространства имён выполняется успешно. Приложение здорово; адреса просто нет в стеке хоста.

Опубликуйте один порт прыжком socat

socat соединяет два стека в пользовательском пространстве, чего достаточно, когда должен пройти один порт TCP. Сторона хоста слушает в LAN и для каждого принятого соединения запускает второй socat внутри пространства имён, который подключается к loopback приложения. Внутренний процесс достигает приложения точно так же, как это сделал бы локальный клиент. В маршрутизации пространства имён ничего не меняется, поэтому приложение продолжает использовать туннель как единственный выход.

socat TCP-LISTEN:9100,reuseaddr,fork EXEC:'ip netns exec vpn socat STDIO tcp-connect:127.0.0.1:9100',nofork

Внешнему процессу нужен root или возможность войти в пространство имён. Если VPN падает, приложение теряет путь, а опубликованный порт отказывает закрытым, и это именно то поведение, которого вы ждёте от тюрьмы.

Используйте пару veth, когда проходит больше одного порта

Пара veth — правильный ответ, когда должны пройти несколько портов или протоколов, или когда другие хосты должны инициировать соединения. Один конец остаётся в хосте, другой переходит в пространство имён, и небольшая /30 даёт обеим сторонам стабильный адрес. Затем маршрут хоста отправляет адрес пространства имён через пару.

ip link add veth0 type veth peer name veth1
ip link set veth1 netns vpn
ip addr add 10.77.0.1/30 dev veth0
ip link set veth0 up
ip netns exec vpn ip addr add 10.77.0.2/30 dev veth1
ip netns exec vpn ip link set veth1 up

Не добавляйте маршрут по умолчанию через хост, если не собираетесь ломать тюрьму. Туннель должен оставаться выходом, поэтому через пару доступен только опубликованный адрес службы. Дайте пространству имён и собственный файл resolver, потому что ip netns exec читает /etc/netns/vpn/resolv.conf, а без него разрешение имён внутри тюрьмы пустое.

Тестируйте со второй машины, а не с хоста

Запускайте тест со второй машины, потому что хост может добраться до локального слушателя путями, которые ничего не говорят о LAN. Сначала проверьте, к чему приложение действительно привязалось внутри пространства имён, затем подключитесь снаружи к опубликованному адресу. Привязка ко всем адресам там не расширяет тюрьму, потому что wildcard всё ещё принадлежит пространству имён, и LAN не может его увидеть.

ip netns exec vpn ss -lntp

Если соединение с хоста работает, а из LAN нет, недостающая часть — это прыжок или маршрут, а не адрес привязки. Запускайте OpenVPN внутри пространства имён, а не переносите туда живое устройство tun, поскольку перенос интерфейса выключает его и может стереть маршруты, которые потом нельзя будет починить снаружи. Держите команды восстановления на консоли, а не внутри тюрьмы.

Похожие статьи