Vaš tunelski kontejner radi, docker compose exec vpn curl -s https://ifconfig.me odgovara adresom provajdera, a preglednik na vašem računalu ipak izlazi kroz vašeg ISP-a. Taj jaz je očekivan. Kontejner koji pokreće VPN klijent drži mrežni imenski prostor, rute i sučelje tunela, i ništa što govori HTTP ili SOCKS; objavljivanje porta na njemu ne može stvoriti slušalac kojeg nikada nije bilo.

Gdje se klijent izvršava odlučuje o dizajnu. Susjedni kontejner može prijeći u imenski prostor tunela, desktop aplikacija ne može, a ruter treba rute, a ne polje proxyja. Pogriješite li mapiranje, simptom je isti: veza odbijena ili promet koji tiho ide starim putem.

Uskladite raspored s mjestom gdje se klijent izvršava

Postavite jedno pitanje prije uređivanja Composea: može li se klijent pokrenuti unutar mrežnog imenskog prostora VPN kontejnera? Sve što već radi kao Linux kontejner može. Preglednik, IDE ili CLI na vašem stolu ne mogu, jer njegova proxy postavka očekuje protokolarnu uslugu, a ne imenski prostor.

ClientArrangementWhat must already exist
Another Compose serviceShares the vpn namespace via network_mode: service:vpnA working tunnel and correct start order
Host browser, IDE or CLIProxy listener inside the namespace, published to host loopbackA configured SOCKS or HTTP proxy and its access rules
Router, VM or phoneThe container as a layer-3 gatewayForwarding, NAT and a return route

Ta se tri ne miješaju. Polje HTTP proxyja usmjereno na bridge adresu kontejnera ne doseže ništa ako tamo ne sluša proxy, a slušalac proxyja ne rutira promet rutera. Prvo odlučite, zatim slijedite odgovarajući odjeljak.

Podijelite imenski prostor tunela sa susjednim kontejnerom

Ovo je najjeftinija opcija jer nije uključen nikakav proxy protokol. Aplikacija se pridružuje imenskom prostoru usluge vpn i nasljeđuje njezina sučelja, rute i prostor portova:

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

Iz toga što imenski prostor pripada drugoj usluzi slijede tri ograničenja. Aplikacija ne dobiva vlastiti ključ networks, jer nema imenski prostor kojem bi se pripojila. Objavljivanje portova pripada vpn-u, jer tamo živi imenski prostor. A ponovno stvaranje vpn-a uništava imenski prostor kojem se aplikacija pridružila, pa docker compose up -d --force-recreate vpn ostavlja vama da ponovno stvorite i app; obično ponovno pokretanje nije uvijek dovoljno. Referenca za Compose usluge pokriva ovaj raspored i njegovo ograničenje objavljivanja portova.

Ne pretpostavljajte da resolver dolazi s njim. /etc/resolv.conf je datoteka po kontejneru, a ne dio mrežnog imenskog prostora, pa aplikacija još može pitati resolver hosta dok njezini paketi izlaze kroz tunel. Pročitajte je unutar kontejnera i postavite dns: na aplikaciji kada se privatna imena moraju razriješiti kroz tunel.

docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.me

Ako popis ruta sadrži sučelje tunela i adresa je provajderova, aplikacija je unutar tunela. Ako sučelje nedostaje, app je pokrenut prije nego što je vpn imao tunel, pa ponovno stvorite app kad vpn prijavi da je zdrav.

Postavite pravi proxy slušalac u imenski prostor za klijente hosta

Desktop preglednik ne može se pridružiti imenskom prostoru, pa tunel mora biti izložen kao usluga. Pokrenite stvarni SOCKS ili HTTP proxy unutar imenskog prostora vpn-a i objavite samo njegov port:

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 na strani hosta važna je polovica tog mapiranja. 127.0.0.1:1080 s lijeve strane drži slušalac izvan vaše LAN mreže; goli "1080:1080" objavljuje otvoreni proxy svakom uređaju koji može dosegnuti vaše računalo.

Strana kontejnera ima vlastitu zamku. Objavljeni portovi dostavljaju se na adresu kontejnera na bridgeu, a ne na njegov loopback, pa proxy pokrenut s --socks 127.0.0.1:1080 unutar imenskog prostora prihvaća veze od susjeda i odbija sve što stiže kroz objavljeni port. Vežite ga na 0.0.0.0 i oslonite se na loopback vezivanje na strani hosta za izolaciju. Isto pravilo vrijedi za adresu slušanja u konfiguracijskoj datoteci proxyja.

Zatim odlučite gdje se imena razrješavaju. U curl-u --socks5 razrješava ime hosta lokalno, a --socks5-hostname šalje ime proxyju; preglednici izlažu istu sklopku pod drugom oznakom. Lokalno razrješavanje odaje upit čak i kad se stranica učita kroz tunel.

Tretirajte kontejner kao kapiju samo s povratnom rutom

Ruteri, VM-ovi i telefoni neće koristiti polje HTTP proxyja, a neke aplikacije potpuno ignoriraju proxy varijable. Rutiranje njihovog prometa znači sloj 3: kontejner prosljeđuje pakete i prevodi adrese na sučelju tunela.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

Dvije stvari se lako propuste. Klijentu treba ruta koja njegovu zadanu kapiju usmjerava na ovaj host, a odgovori moraju naći put natrag, bilo kroz statičku rutu na uzvodnom ruteru ili kroz NAT na sučelju prema klijentima. Bez jednog od toga tunel nosi zahtjev van i odgovor nestaje.

Ima i najširi radijus djelovanja. Host koji služi kao kapija za cijelu LAN mrežu šalje svakog pogrešno konfiguriranog klijenta kroz vaš VPN račun, a pad tunela ili blokira LAN ili se vraća na ISP, ovisno o kill switchu.

Provjerite izlaznu putanju, pa se vraćajte redom

Provjeravajte ovim redom i zaustavite se na prvom neuspjehu: izlazna adresa unutar imenskog prostora, izlazna adresa s hosta kroz proxy, zatim razrješavanje imena za privatni 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/health

Prve dvije adrese trebaju odgovarati provajderu, a treća se treba razriješiti kroz proxy umjesto da padne s greškom imena. Podudaranje prvog retka i neuspjeh drugog znači da je slušalac ili objavljeni port pogrešan, a ne tunel.

Vraćanje je obrnuto od postavljanja. Uklonite proxy varijable okoline iz profila ljuske i iz bilo koje systemd jedinice, zatim spustite stog da zajednički imenski prostor nestane sa svojim vlasnikom. Obrišite objavljeni port prije brisanja proxy usluge, inače host zadržava loopback slušalac koji nitko ne čita.

Prije nego nastavite, potvrdite četiri stvari: klijent do kojeg vam je stalo doista doseže tunel, samo vlasnik imenskog prostora objavljuje portove, privatna imena se razrješavaju gdje ste namjeravali i ništa ne sluša na adresi hosta koja nije loopback. Svaka od tih stvari tiho pada u produkciji, a svaka je provjera od jednog retka gore.

Povezani članci