Як накіраваць трафік хоста праз кантэйнер Docker з VPN
Кантэйнер VPN — гэта сеткавая прастора імён, а не проксі. Выберыце агульную netns, сапраўдны слухач SOCKS або маршрутызаваны шлюз, потым праверце шлях выхаду.
Ваш кантэйнер тунеля працуе, docker compose exec vpn curl -s https://ifconfig.me адказвае адрасам правайдэра, а браўзер на працоўным стале ўсё яшчэ выходзіць праз вашага інтэрнэт-правайдэра. Гэты разрыў чаканы. Кантэйнер, які запускае кліент VPN, трымае сеткавую прастору імён, маршруты і інтэрфейс тунеля, і нічога, што размаўляе HTTP ці SOCKS; апублікаваць порт на ім не можа стварыць слухача, якога ніколі не было.
Дзе працуе кліент, тое вызначае архітэктуру. Блізкі кантэйнер можа перайсці ў прастору імён тунеля, праграма на працоўным стале не можа, а маршрутызатару патрэбныя маршруты, а не поле проксі. Памыліцеся з супастаўленнем — сімптом той самы: злучэнне адхіленае або трафік ціха ідзе старым шляхам.
Суаднясіце схему з месцам запуску кліента
Задайце адно пытанне перад рэдагаваннем Compose: ці можна запусціць кліент унутры сеткавай прасторы імён кантэйнера VPN? Усё, што ўжо працуе як кантэйнер Linux, можа. Браўзер, IDE ці CLI на вашым стале не могуць, бо яго налада проксі чакае пратакольны сэрвіс, а не прастору імён.
| Client | Arrangement | What must already exist |
|---|---|---|
| Another Compose service | Shares the vpn namespace via network_mode: service:vpn | A working tunnel and correct start order |
| Host browser, IDE or CLI | Proxy listener inside the namespace, published to host loopback | A configured SOCKS or HTTP proxy and its access rules |
| Router, VM or phone | The container as a layer-3 gateway | Forwarding, NAT and a return route |
Гэтыя тры не змешваюцца. Поле проксі HTTP, накіраванае на адрас моста кантэйнера, не дасягае нічога, пакуль там не слухае проксі, а слухач проксі не маршрутызуе трафік маршрутызатара. Спачатку вырашыце, потым ідзіце па адпаведным раздзеле.
Падзяліце прастору імён тунеля з блізкім кантэйнерам
Гэта самы танны варыянт, бо ніякі пратакол проксі не задзейнічаны. Праграма далучаецца да прасторы імён сэрвісу vpn і атрымлівае яго інтэрфейсы, маршруты і прастору партоў:
services:
vpn:
image: your-vpn-client
cap_add:
- NET_ADMIN
healthcheck:
test: ["CMD-SHELL", "ip link show tun0 >/dev/null"]
interval: 10s
retries: 5
app:
image: your-app
network_mode: service:vpn
depends_on:
vpn:
condition: service_healthyЗ таго, што прастора імён належыць іншаму сэрвісу, вынікаюць тры абмежаванні. Праграма не атрымлівае ўласнага ключа networks, бо ў яе няма прасторы імён, да якой далучыцца. Публікацыя партоў належыць vpn, бо менавіта там жыве прастора імён. І перастварэнне vpn знішчае прастору імён, да якой далучылася праграма, таму docker compose up -d --force-recreate vpn пакідае вам перастварыць і app; звычайнага перазапуску не заўсёды дастаткова. Даведнік па сэрвісах Compose апісвае гэту схему і абмежаванне на публікацыю партоў.
Не мяркуйце, што рэзалвер ідзе разам. /etc/resolv.conf — гэта файл асобнага кантэйнера, а не частка сеткавай прасторы імён, таму праграма ўсё яшчэ можа пытаць рэзалвер хоста, пакуль яе пакеты выходзяць праз тунель. Прачытайце яго знутры кантэйнера і задайце dns: для праграмы, калі прыватныя імёны павінны вырашацца праз тунель.
docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.meКалі спіс маршрутаў змяшчае інтэрфейс тунеля, а адрас — правайдэра, праграма ўнутры тунеля. Калі інтэрфейса няма, app запусціўся раней, чым vpn атрымаў тунель, таму перастварыце app, як толькі vpn паведаміць пра здароўе.
Размясціце сапраўдны слухач проксі ў прасторы імён для кліентаў хоста
Браўзер на працоўным стале не можа далучыцца да прасторы імён, таму тунель трэба выставіць як сэрвіс. Запусціце сапраўдны проксі SOCKS ці HTTP унутры прасторы імён vpn і апублікуйце толькі яго порт:
services:
vpn:
ports:
- "127.0.0.1:1080:1080"
proxy:
image: your-proxy
network_mode: service:vpn
command: ["--socks", "0.0.0.0:1080"]Адрас на баку хоста — важная палова гэтага супастаўлення. 127.0.0.1:1080 злева трымае слухача па-за вашай LAN; голы "1080:1080" публікуе адкрыты проксі для кожнай прылады, што можа дасягнуць вашай машыны.
У боку кантэйнера свая пастка. Апублікаваныя парты дастаўляюцца на адрас кантэйнера на мосце, а не на яго loopback, таму проксі, запушчаны з --socks 127.0.0.1:1080 унутры прасторы імён, прымае злучэнні ад блізкіх кантэйнераў і адхіляе ўсё, што прыходзіць праз апублікаваны порт. Прывязайце яго да 0.0.0.0 і спадзявайцеся на прывязку loopback на баку хоста для ізаляцыі. Тое ж правіла датычыцца адраса праслухоўвання ў файле канфігурацыі проксі.
Потым вырашыце, дзе вырашаюцца імёны. У curl --socks5 вырашае імя хоста лакальна, а --socks5-hostname адпраўляе імя проксі; браўзеры паказваюць тую ж опцыю пад іншай назвай. Лакальнае рашэнне выдае запыт нават тады, калі старонка грузіцца праз тунель.
Разглядайце кантэйнер як шлюз толькі з маршрутам вяртання
Маршрутызатары, VM і тэлефоны не будуць карыстацца полем проксі HTTP, а некаторыя праграмы цалкам ігнаруюць зменныя проксі. Маршрутызаваць іх трафік — значыць узровень 3: кантэйнер перасылае пакеты і перакладае адрасы на інтэрфейсе тунеля.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADEДзве рэчы лёгка прапусціць. Кліенту патрэбны маршрут, які накіроўвае яго шлюз па змаўчанні на гэты хост, а адказы павінны знайсці шлях назад — праз статычны маршрут на верхнім маршрутызатары або праз NAT на інтэрфейсе, скіраваным да кліентаў. Без аднаго з гэтага тунель выносіць запыт вонкі, і адказ знікае.
У яго таксама самы шырокі радыус уздзеяння. Хост у ролі шлюза для ўсёй LAN праводзіць кожнага няправільна наладжанага кліента праз ваш уліковы запіс VPN, а падзенне тунеля або блакуе LAN, або вяртаецца да правайдэра — у залежнасці ад kill switch.
Праверце шлях выхаду, потым адкочвайце па парадку
Правярайце ў гэтым парадку і спыніцеся на першай няўдачы: адрас выхаду ўнутры прасторы імён, адрас выхаду з хоста праз проксі, потым рашэнне імён для прыватнага хоста.
docker compose exec vpn curl -s https://ifconfig.me
curl -s -x socks5h://127.0.0.1:1080 https://ifconfig.me
curl -s -x socks5h://127.0.0.1:1080 http://internal.example/healthПершыя два адрасы павінны супадаць з правайдэрам, а трэці — вырашацца праз проксі, а не падаць з памылкай імені. Супадзенне першага радка і няўдача другога азначаюць, што няправільны слухач або апублікаваны порт, а не тунель.
Адкот — гэта адваротнае да наладжвання. Выдаліце зменныя асяроддзя проксі з профілю абалонкі і з любога модуля systemd, потым апусціце стэк, каб агульная прастора імён знікла разам з уладальнікам. Выдаліце апублікаваны порт перад выдаленнем сэрвісу проксі, інакш хост пакіне слухач loopback, які ніхто не чытае.
Перш чым ісці далей, пацвердзіце чатыры рэчы: кліент, які вас цікавіць, сапраўды дасягае тунеля, парты публікуе толькі ўладальнік прасторы імён, прыватныя імёны вырашаюцца там, дзе вы хацелі, і нішто не слухае на адрасе хоста, не loopback. Кожнае з гэтага ціха правальваецца ў прадукцыі, і кожнае — праверка ў адзін радок вышэй.