С приложением всё в порядке, и с туннелем всё в порядке, а панель всё равно не загружается. Когда служба работает с network_mode: service:vpn, она делит сетевое пространство имён контейнера VPN, то есть её слушатель и опубликованные порты принадлежат этому пространству имён, а не службе. Отсюда следуют три решения: где привязывается приложение, какой контейнер публикует порт и насколько узок путь управления. Расставьте их в неверном порядке, и каждая отдельная настройка выглядит правильной, хотя сочетание работать не может.

Кому принадлежит пространство имён порта

В общем пространстве имён добавление записи ports: зависимой службе ничего полезного не даёт, а несколько сетевых параметров для неё не поддерживаются по замыслу. Публикуйте вместо этого на контейнере, которому принадлежит пространство имён. Этот же контейнер — тот, чей адрес появляется на хосте, поэтому сопоставление читается как одна запись, а не одна на каждую службу.

services:
  vpn:
    image: vpn-client-image
    cap_add: [NET_ADMIN]
    ports:
      - "127.0.0.1:8080:8080"
  app:
    network_mode: "service:vpn"

Обратите внимание на адрес слева от сопоставления. Привязка к 127.0.0.1 оставляет опубликованный порт на loopback хоста, что обычно и нужно интерфейсу управления. Привязка к 0.0.0.0 открывает его на всех интерфейсах хоста, и это другое решение по безопасности, а не удобство.

Заставьте приложение слушать там, где пространство имён этого ждёт

Слушатель, привязанный к 127.0.0.1 внутри пространства имён, доступен только изнутри этого пространства. Опубликованные порты хоста приходят снаружи, поэтому приложение должно привязать более широкий адрес, чтобы сопоставление работало. На большинстве серверов это правка в одну строку, и именно этот шаг пропускают после копирования руководства по усилению, написанного для развёртывания без контейнеров.

docker compose exec app ss -lntp
docker port vpn
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/

Список слушателей внутри приложения говорит правду об адресе привязки, а docker port показывает, что владелец действительно опубликовал. Если первый показывает 127.0.0.1, а второй показывает сопоставление на хосте, вы нашли несоответствие, не трогая конфигурацию VPN.

Выберите, как входит путь управления

Есть три разумных варианта. Публикуйте на контейнере VPN и добирайтесь до него с хоста или из локальной сети. Поставьте обратный прокси перед пространством имён и отдайте прокси единственный открытый порт. Либо держите панель доступной только изнутри пространства имён через сеанс exec или туннель SSH, что даёт наименьшее раскрытие и наименьшие удобства.

Какой подойдёт, зависит от того, кому и откуда нужен интерфейс. Одному администратору на том же хосте достаточно привязки к loopback. Команде, которая добирается через VPN, нужен продуманный путь и названный владелец. Выбор варианта с прокси даёт TLS и журналы доступа, но требует ещё одного компонента, который нужно поддерживать в актуальном состоянии.

Откройте порт управления, не открывая всё

Собственная политика локального доступа или блокировки VPN-клиента может отбросить входящий запрос управления, даже когда исходящий туннель работает безупречно. Разрешите одно документированное исключение для нужного источника и порта, затем подтвердите, что обычная защита туннеля не изменилась. Отключение аварийного выключателя ради загрузки панели меняет реальный контроль на вкладку браузера.

Оставьте собственную аутентификацию приложения включённой. Нахождение внутри стека, подключённого к VPN, не даёт прав каждому локальному пользователю и каждому устройству, которое может добраться до хоста, а панель администратора без аутентификации за туннелем остаётся панелью без аутентификации.

Проверьте с устройства управления, а затем проверьте ещё раз позже

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

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

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