Paano i-route ang trapiko ng host sa pamamagitan ng Docker VPN container
Ang VPN container ay isang network namespace, hindi proxy. Pumili ng shared netns, tunay na SOCKS listener o naka-route na gateway, pagkatapos i-verify ang exit path.
Gumagana ang tunnel container mo, sumasagot ang docker compose exec vpn curl -s https://ifconfig.me gamit ang address ng provider, at palabas pa rin ang browser sa desktop mo sa ISP mo. Inaasahan ang puwang na iyon. Ang container na nagpapatakbo ng VPN client ay may hawak na network namespace, mga ruta at tunnel interface, at walang anumang nagsasalita ng HTTP o SOCKS; ang pag-publish ng port dito ay hindi makakalikha ng listener na hindi kailanman umiral.
Kung saan tumatakbo ang client ang nagtatakda ng disenyo. Ang katabing container ay makakapasok sa namespace ng tunnel, ang desktop application ay hindi, at ang router ay nangangailangan ng mga ruta hindi proxy field. Kung mali ang mapping, pareho ang sintomas: connection refused, o trapikong tahimik na dumadaan sa lumang ruta.
Itugma ang kaayusan sa lugar kung saan tumatakbo ang client
Magtanong ng isa bago i-edit ang Compose: maaari bang simulan ang client sa loob ng network namespace ng VPN container? Anumang tumatakbo na bilang Linux container ay kaya. Ang browser, IDE o CLI sa mesa mo ay hindi kaya, dahil ang setting ng proxy nito ay umaasa sa serbisyo ng protocol, hindi namespace.
| 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 |
Hindi naghahalo ang tatlong ito. Ang HTTP proxy field na naka-address sa bridge address ng container ay walang naaabot maliban kung may proxy na nakikinig doon, at ang proxy listener ay hindi nag-route ng trapiko ng router. Magpasya muna, pagkatapos sundan ang tugmang seksyon.
Ibahagi ang tunnel namespace sa katabing container
Ito ang pinakamurang opsyon dahil walang protocol ng proxy na kasangkot. Pumapasok ang app sa namespace ng serbisyong vpn at namamana ang mga interface, ruta at puwang ng port nito:
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_healthyTatlong paghihigpit ang sumusunod sa katotohanang pag-aari ng ibang serbisyo ang namespace. Hindi nakakakuha ang app ng sarili nitong networks key, dahil wala itong namespace na kakabitan. Ang pag-publish ng port ay pag-aari ng vpn, dahil doon nakatira ang namespace. At ang muling paggawa ng vpn ay sumisira sa namespace na pinasukan ng app, kaya docker compose up -d --force-recreate vpn ay nag-iiwan sa iyo na gawing muli ang app; ang simpleng restart ay hindi laging sapat. Sinasaklaw ng reference ng mga serbisyo ng Compose ang kaayusang ito at ang paghihigpit nito sa pag-publish ng port.
Huwag ipagpalagay na kasama ang resolver. Ang /etc/resolv.conf ay file kada container, hindi bahagi ng network namespace, kaya maaari pa ring tanungin ng app ang resolver ng host habang lumalabas ang mga packet nito sa tunnel. Basahin ito mula sa loob ng container at itakda ang dns: sa app kapag ang mga pribadong pangalan ay dapat lutasin sa tunnel.
docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.meKung ang listahan ng ruta ay may tunnel interface at ang address ay sa provider, nasa loob ng tunnel ang app. Kung wala ang interface, nagsimula ang app bago nagkaroon ng tunnel ang vpn, kaya gawing muli ang app kapag iniulat ng vpn na malusog ito.
Maglagay ng tunay na proxy listener sa namespace para sa mga kliyente ng host
Hindi makakasali ang desktop browser sa namespace, kaya dapat ilantad ang tunnel bilang serbisyo. Magpatakbo ng tunay na SOCKS o HTTP proxy sa loob ng vpn namespace at i-publish lamang ang port nito:
services:
vpn:
ports:
- "127.0.0.1:1080:1080"
proxy:
image: your-proxy
network_mode: service:vpn
command: ["--socks", "0.0.0.0:1080"]Ang address sa panig ng host ang mahalagang kalahati ng mapping na iyon. Ang 127.0.0.1:1080 sa kaliwa ay naglalayo sa listener mula sa LAN mo; ang hubad na "1080:1080" ay nag-publish ng bukas na proxy sa bawat device na makakaabot sa makina mo.
May sariling bitag ang panig ng container. Ang mga na-publish na port ay hinahatid sa address ng container sa bridge, hindi sa loopback nito, kaya ang proxy na sinimulan gamit ang --socks 127.0.0.1:1080 sa loob ng namespace ay tumatanggap ng koneksyon mula sa mga kapatid at tinatanggihan ang lahat ng dumarating sa na-publish na port. Itali ito sa 0.0.0.0 at umasa sa loopback binding sa panig ng host para sa paghihiwalay. Ganoon din ang tuntunin sa listen address sa isang proxy config file.
Pagkatapos ay magpasya kung saan nilulutas ang mga pangalan. Sa curl, nilulutas ng --socks5 ang hostname nang lokal at ipinapadala ng --socks5-hostname ang pangalan sa proxy; ipinapakita ng mga browser ang parehong switch sa ibang label. Ang lokal na resolusyon ay naglalabas ng query kahit na naglo-load ang pahina sa tunnel.
Ituring ang container na gateway lamang kapag may ruta pabalik
Ang mga router, VM at telepono ay hindi gagamit ng HTTP proxy field, at ang ilang application ay lubusang binabalewala ang mga proxy variable. Ang pag-route ng kanilang trapiko ay nangangahulugang layer 3: ipinapasa ng container ang mga packet at isinasalin ang mga address sa tunnel interface.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADEDalawang bagay ang madaling makaligtaan. Kailangan ng client ng rutang itinuturo ang default gateway nito sa host na ito, at ang mga sagot ay dapat makahanap ng daan pabalik, sa pamamagitan ng static route sa upstream router o ng NAT sa interface na nakaharap sa mga client. Kung wala ang isa sa dalawa, dinadala ng tunnel ang kahilingan palabas at nawawala ang sagot.
May pinakamalawak din itong saklaw ng epekto. Ang host na nagsisilbing gateway para sa buong LAN ay nagpapadala ng bawat maling naka-configure na client sa account ng VPN mo, at ang pagbagsak ng tunnel ay nagpapadilim sa LAN o bumabalik sa ISP depende sa kill switch.
I-verify ang exit path, pagkatapos ay i-roll back ayon sa pagkakasunod-sunod
Suriin sa ayos na ito at huminto sa unang pagkabigo: exit address sa loob ng namespace, exit address mula sa host sa pamamagitan ng proxy, pagkatapos ay resolusyon ng pangalan para sa pribadong host.
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/healthDapat tumugma ang unang dalawang address sa provider, at ang pangatlo ay dapat malutas sa proxy sa halip na mabigo sa error ng pangalan. Ang unang linya ay tumutugma at ang pangalawa ay nabigo ay nangangahulugang mali ang listener o ang na-publish na port, hindi ang tunnel.
Ang pag-roll back ay kabaligtaran ng setup. Alisin ang proxy environment variables sa shell profile at sa anumang systemd unit, pagkatapos ay ibaba ang stack upang mawala ang shared namespace kasama ang may-ari nito. Burahin ang na-publish na port bago burahin ang proxy service, kung hindi ay may natitirang loopback listener ang host na walang nagbabasa.
Bago magpatuloy, tiyakin ang apat na bagay: ang client na mahalaga sa iyo ay talagang nakakaabot sa tunnel, ang may-ari lamang ng namespace ang nag-publish ng mga port, ang mga pribadong pangalan ay nalulutas sa lugar na nilayon mo, at walang nakikinig sa host address na hindi loopback. Bawat isa sa mga ito ay tahimik na nabibigo sa produksyon, at bawat isa ay isang linyang pagsusuri sa itaas.