Så dirigerar du värdtrafik genom en Docker VPN-container
En VPN-container är en nätverksnamnrymd, inte en proxy. Välj ett delat netns, en riktig SOCKS-lyssnare eller en routad gateway och verifiera sedan utgångsvägen.
Din tunnelcontainer fungerar, docker compose exec vpn curl -s https://ifconfig.me svarar med leverantörens adress, och ändå lämnar webbläsaren på skrivbordet din ISP. Den klyftan är väntad. En container som kör en VPN-klient håller en nätverksnamnrymd, rutter och ett tunnelgränssnitt, och inget som talar HTTP eller SOCKS; att publicera en port på den kan inte skapa en lyssnare som aldrig fanns.
Var klienten kör avgör designen. En syskoncontainer kan flytta in i tunnelns namnrymd, en skrivbordsapplikation kan inte, och en router behöver rutter framför ett proxyfält. Får du mappningen fel är symptomet detsamma: anslutning nekad, eller trafik som tyst tar den gamla vägen.
Anpassa arrangemanget till platsen där klienten kör
Ställ en fråga innan du redigerar Compose: kan klienten startas inne i VPN-containerns nätverksnamnrymd? Allt som redan körs som en Linux-container kan. En webbläsare, en IDE eller en CLI på skrivbordet kan inte, eftersom dess proxyinställning väntar sig en protokolltjänst, inte en namnrymd.
| 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 |
Dessa tre blandas inte. Ett HTTP-proxyfält riktat mot containerns broddress når ingenting om ingen proxy lyssnar där, och en proxylyssnare routar inte en routers trafik. Bestäm först och följ sedan motsvarande avsnitt.
Dela tunnelns namnrymd med en syskoncontainer
Detta är det billigaste alternativet eftersom ingen proxyprotokoll är inblandad. Appen går in i vpn-tjänstens namnrymd och ärver dess gränssnitt, rutter och portutrymme:
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_healthyTre begränsningar följer av att namnrymden tillhör en annan tjänst. Appen får ingen egen networks-nyckel, eftersom den inte har någon namnrymd att fästa vid. Portpublicering hör till vpn, eftersom det är där namnrymden bor. Och att återskapa vpn förstör namnrymden som appen gick in i, så docker compose up -d --force-recreate vpn lämnar till dig att återskapa app också; en vanlig omstart är inte alltid nog. Compose-tjänstreferensen täcker detta arrangemang och dess begränsning för portpublicering.
Anta inte att resolveraren följer med. /etc/resolv.conf är en fil per container, inte en del av nätverksnamnrymden, så appen kan fortfarande fråga värdens resolver medan dess paket lämnar genom tunneln. Läs den inne i containern och sätt dns: på appen när privata namn måste lösas genom tunneln.
docker compose exec app ip route
docker compose exec app cat /etc/resolv.conf
docker compose exec app curl -s https://ifconfig.meOm ruttlistan innehåller tunnelgränssnittet och adressen är leverantörens är appen inne i tunneln. Om gränssnittet saknas startade app innan vpn hade en tunnel, så återskapa app när vpn rapporterar att den är frisk.
Sätt en riktig proxylyssnare i namnrymden för värdklienter
En skrivbordswebbläsare kan inte gå med i en namnrymd, så tunneln måste exponeras som en tjänst. Kör en riktig SOCKS- eller HTTP-proxy inne i vpn-namnrymden och publicera bara dess 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"]Adressen på värdsidan är den viktiga hälften av den mappningen. 127.0.0.1:1080 till vänster håller lyssnaren utanför ditt LAN; en naken "1080:1080" publicerar en öppen proxy till varje enhet som kan nå din maskin.
Containersidan har sin egen fälla. Publicerade portar levereras till containerns adress på bryggan, inte till dess loopback, så en proxy startad med --socks 127.0.0.1:1080 i namnrymden accepterar anslutningar från syskon och nekar allt som kommer genom den publicerade porten. Bind den till 0.0.0.0 och lita på loopback-bindningen på värdsidan för isolering. Samma regel gäller lyssnaradressen i en proxykonfigurationsfil.
Bestäm sedan var namn löses. I curl löser --socks5 värdnamnet lokalt och --socks5-hostname skickar namnet till proxyn; webbläsare visar samma växel under en annan etikett. Lokal upplösning läcker frågan även när sidan laddas genom tunneln.
Behandla containern som gateway bara med en returrutt
Routrar, VM:ar och telefoner kommer inte att använda ett HTTP-proxyfält, och vissa applikationer ignorerar proxyvariabler helt. Att routa deras trafik betyder lager 3: containern vidarebefordrar paket och översätter adresser på tunnelgränssnittet.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADETvå saker missas lätt. Klienten behöver en rutt som pekar dess standardgateway mot denna värd, och svar måste hitta vägen tillbaka, antingen via en statisk rutt på uppströmsroutern eller via NAT på gränssnittet mot klienterna. Utan en av dem bär tunneln ut begäran och svaret försvinner.
Den har också den bredaste effekten. En värd som fungerar som gateway för hela LAN skickar varje felkonfigurerad klient genom ditt VPN-konto, och ett tunnelfall antingen mörklägger LAN eller faller tillbaka till ISP beroende på kill switch.
Verifiera utgångsvägen och rulla sedan tillbaka i ordning
Kontrollera i denna ordning och stanna vid första felet: utgångsadress inne i namnrymden, utgångsadress från värden genom proxyn, sedan namnlösning för en privat värd.
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/healthDe två första adresserna ska matcha leverantören, och den tredje ska lösas genom proxyn i stället för att misslyckas med ett namnfela. En matchande första rad och en misslyckad andra rad betyder att lyssnaren eller den publicerade porten är fel, inte tunneln.
Tillbakarullning är motsatsen till uppsättningen. Ta bort proxy-miljövariablerna från skalprofilen och från varje systemd-enhet, och ta sedan ner stacken så att den delade namnrymden försvinner med sin ägare. Radera den publicerade porten innan du raderar proxytjänsten, annars behåller värden en loopback-lyssnare som ingen läser.
Innan du går vidare, bekräfta fyra saker: klienten du bryr dig om når faktiskt tunneln, bara namnrymdens ägare publicerar portar, privata namn löses där du hade tänkt, och inget lyssnar på en värdadress som inte är loopback. Var och en av dem misslyckas tyst i produktion, och var och en är en enradskontroll ovan.