Cum să direcționezi traficul gazdei printr-un container Docker VPN
Un container VPN este un spațiu de nume de rețea, nu un proxy. Alegeți un netns partajat, un ascultător SOCKS real sau o poartă rutată, apoi verificați calea de ieșire.
Containerul de tunel funcționează, docker compose exec vpn curl -s https://ifconfig.me răspunde cu adresa furnizorului, și totuși browserul de pe birou iese prin ISP-ul dumneavoastră. Acest decalaj este de așteptat. Un container care rulează un client VPN ține un spațiu de nume de rețea, rute și o interfață de tunel, și nimic care vorbește HTTP sau SOCKS; publicarea unui port pe el nu poate crea un ascultător care nu a existat niciodată.
Unde rulează clientul decide proiectarea. Un container frate poate intra în spațiul de nume al tunelului, o aplicație desktop nu poate, iar un router are nevoie de rute, nu de un câmp de proxy. Dacă greșiți maparea, simptomul este același: conexiune refuzată sau trafic care ia în liniște vechea cale.
Potriviți aranjamentul cu locul unde rulează clientul
Puneți o întrebare înainte de a edita Compose: poate clientul fi pornit în interiorul spațiului de nume de rețea al containerului VPN? Orice rulează deja ca container Linux poate. Un browser, un IDE sau un CLI pe biroul dumneavoastră nu poate, pentru că setarea de proxy așteaptă un serviciu de protocol, nu un spațiu de nume.
| 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 |
Aceste trei nu se amestecă. Un câmp de proxy HTTP îndreptat spre adresa de punte a containerului nu ajunge la nimic dacă acolo nu ascultă un proxy, iar un ascultător de proxy nu rutează traficul unui router. Decideți mai întâi, apoi urmați secțiunea potrivită.
Partajați spațiul de nume al tunelului cu un container frate
Aceasta este cea mai ieftină opțiune pentru că nu este implicat niciun protocol de proxy. Aplicația intră în spațiul de nume al serviciului vpn și moștenește interfețele, rutele și spațiul de porturi:
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_healthyTrei restricții decurg din faptul că spațiul de nume aparține altui serviciu. Aplicația nu primește o cheie networks proprie, pentru că nu are un spațiu de nume de care să se atașeze. Publicarea porturilor aparține vpn-ului, fiindcă acolo trăiește spațiul de nume. Iar recrearea vpn-ului distruge spațiul de nume în care a intrat aplicația, așa că docker compose up -d --force-recreate vpn vă lasă să recreați și app; o repornire simplă nu este întotdeauna suficientă. Referința serviciilor Compose acoperă acest aranjament și restricția lui privind publicarea porturilor.
Nu presupuneți că rezolvatorul vine cu el. /etc/resolv.conf este un fișier per container, nu parte a spațiului de nume de rețea, așa că aplicația poate încă întreba rezolvatorul gazdei în timp ce pachetele ei ies prin tunel. Citiți-l din interiorul containerului și setați dns: pe aplicație când numele private trebuie rezolvate prin tunel.
docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.meDacă lista de rute conține interfața tunelului și adresa este a furnizorului, aplicația este în interiorul tunelului. Dacă interfața lipsește, app a pornit înainte ca vpn-ul să aibă un tunel, așa că recreați app imediat ce vpn-ul raportează că este sănătos.
Puneți un ascultător de proxy real în spațiul de nume pentru clienții gazdei
Un browser de birou nu poate intra într-un spațiu de nume, așa că tunelul trebuie expus ca serviciu. Rulați un proxy SOCKS sau HTTP real în spațiul de nume vpn și publicați doar portul lui:
services:
vpn:
ports:
- "127.0.0.1:1080:1080"
proxy:
image: your-proxy
network_mode: service:vpn
command: ["--socks", "0.0.0.0:1080"]Adresa din partea gazdei este jumătatea importantă a acelei mapări. 127.0.0.1:1080 în stânga ține ascultătorul în afara LAN-ului; un "1080:1080" gol publică un proxy deschis fiecărui dispozitiv care poate ajunge la mașina dumneavoastră.
Partea containerului are propria capcană. Porturile publicate sunt livrate la adresa containerului pe punte, nu la loopback-ul lui, așa că un proxy pornit cu --socks 127.0.0.1:1080 în spațiul de nume acceptă conexiuni de la frați și refuză tot ce sosește prin portul publicat. Legați-l de 0.0.0.0 și bazați-vă pe legarea loopback din partea gazdei pentru izolare. Aceeași regulă se aplică adresei de ascultare dintr-un fișier de configurare a proxy-ului.
Apoi decideți unde sunt rezolvate numele. În curl, --socks5 rezolvă numele gazdei local și --socks5-hostname trimite numele la proxy; browserele expun același comutator sub altă etichetă. Rezolvarea locală scurge interogarea chiar și când pagina se încarcă prin tunel.
Tratați containerul ca poartă doar cu o rută de întoarcere
Routerele, VM-urile și telefoanele nu vor folosi un câmp de proxy HTTP, iar unele aplicații ignoră complet variabilele de proxy. Rutarea traficului lor înseamnă stratul 3: containerul transmite pachete și traduce adrese pe interfața tunelului.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADEDouă lucruri scapă ușor. Clientul are nevoie de o rută care să îi îndrepte poarta implicită spre această gazdă, iar răspunsurile trebuie să găsească drumul înapoi, fie printr-o rută statică pe routerul de deasupra, fie prin NAT pe interfața orientată spre clienți. Fără una dintre ele, tunelul duce cererea afară și răspunsul dispare.
Are și cel mai larg radius de impact. O gazdă care servește drept poartă pentru tot LAN-ul trimite fiecare client configurat greșit prin contul dumneavoastră VPN, iar o cădere a tunelului fie întunecă LAN-ul, fie revine la ISP în funcție de kill switch.
Verificați calea de ieșire, apoi derulați înapoi în ordine
Verificați în această ordine și opriți-vă la primul eșec: adresa de ieșire în spațiul de nume, adresa de ieșire de la gazdă prin proxy, apoi rezolvarea numelor pentru o gazdă privată.
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/healthPrimele două adrese trebuie să corespundă furnizorului, iar a treia trebuie rezolvată prin proxy în loc să eșueze cu o eroare de nume. O primă linie care corespunde și o a doua care eșuează înseamnă că ascultătorul sau portul publicat este greșit, nu tunelul.
Derularea înapoi este inversul configurării. Eliminați variabilele de mediu pentru proxy din profilul shell-ului și din orice unitate systemd, apoi coborâți stiva ca spațiul de nume partajat să dispară cu proprietarul lui. Ștergeți portul publicat înainte de a șterge serviciul de proxy, altfel gazda păstrează un ascultător loopback pe care nimeni nu îl citește.
Înainte de a continua, confirmați patru lucruri: clientul care vă interesează ajunge într-adevăr la tunel, doar proprietarul spațiului de nume publică porturi, numele private se rezolvă unde ați intenționat, și nimic nu ascultă pe o adresă de gazdă care nu este loopback. Fiecare dintre ele eșuează în tăcere în producție, și fiecare este o verificare de o linie mai sus.