Docker sa VPN: Bakit Nawawala ang Mga Port
Alamin kung bakit nawawala ang published ports at service name sa network_mode: service:gluetun, at tingnan ang gumaganang Compose setup para sa Gluetun v3.41.3.
Bakit nawawala ang mga port kapag niruruta ang Docker containers sa VPN
Para i-route ang Docker containers sa VPN, ilagay muna ang tunnel sa isang container. Pagkatapos, i-attach ang iba pang container sa network namespace nito gamit ang network_mode: "service:gluetun". Ang attachment na ito ang karaniwang nakalilito. Kapag naka-attach ang isang container, wala na itong sariling network. Dahil dito, nawawala rin ang mga published port nito at ang Docker service name nito. I-publish ang mga port sa VPN container sa halip. Maa-access naman ng ibang container ang app gamit ang pangalan ng VPN container.
Mag-iwan ng ports: block sa naka-attach na container at tatanggi ang Docker na likhain ito:
Error response from daemon: conflicting options: port publishing and the container type network modeAng tool dito ay Gluetun, isang container na kumokonekta sa commercial VPN (virtual private network) provider gamit ang WireGuard o OpenVPN at may sarili itong firewall. Ang Release v3.41.3 ang kasalukuyang bersyon noong August 2026. Gumagamit ang mga halimbawa ng Mullvad at WireGuard, kaya kailangan mo ng account at key mula sa iyong provider. Kung mas nais mong i-terminate ang tunnel sa hardware na pagmamay-ari mo, ginagawa ng pagpapatakbo ng sarili mong WireGuard server sa isang VPS ang kabilang endpoint. Ang wg-easy sa Docker naman ang naglalagay ng web interface para rito.
Ano talaga ang ginagawa ng network_mode: "service:gluetun"
Karaniwang may sariling network namespace ang bawat Docker container: sarili nitong interfaces, routing table, firewall rules, at listening sockets. Nilalaktawan ng mode na service: ang hakbang na iyon at sinisimulan ang container sa loob ng namespace ng gluetun. Ibig sabihin, iisa ang namespace at iisa ang IP address. Dahil dito, nagbabago ang anim na bagay.
- Walang sariling address ang app. Ang address nito ay address ng gluetun.
- Hindi nakakonekta ang app sa anumang Docker network, kaya hindi nirerehistro at hindi nare-resolve ang service name nito. Dapat gamitin ng ibang container ang
gluetun. - Nagkaka-access ang mga container sa loob ng namespace sa isa't isa gamit ang
localhost. - Hindi maaaring makinig sa parehong port ang dalawang container na nasa iisang namespace. Malinaw ang Gluetun documentation tungkol dito: walang workaround.
- Ang capabilities ay pagmamay-ari ng container, hindi ng namespace. Hawak ng Gluetun ang
NET_ADMINat/dev/net/tundahil ito ang gumagawa ng tunnel interface. Hindi namamana ng naka-attach na container ang mga ito. - Tinatanggihan ng Compose ang anumang file kung nagse-set ang isang service ng parehong
network_modeatnetworks. Ikonekta ang gluetun sa iyong mga network, at sasabay dito ang app.
Kapag nire-restart ang gluetun, nadidiskonekta ang lahat ng naka-attach dito. Dokumentado ang behavior na ito, at ito ang dahilan kung bakit nire-restart ng gluetun ang VPN process sa loob ng container sa halip na lumabas kapag nabigo ang connection. Pagkatapos mong i-restart o i-recreate ang gluetun, i-restart ang mga container na naka-attach dito.
Gumaganang compose file
services:
gluetun:
image: qmcgaw/gluetun:v3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=mullvad
- VPN_TYPE=wireguard
- SERVER_CITIES=Amsterdam
- TZ=Europe/Amsterdam
env_file:
- ./gluetun.env
volumes:
- ./gluetun:/gluetun
ports:
- 127.0.0.1:8080:8080/tcp
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
- WEBUI_PORT=8080
volumes:
- ./qbittorrent:/config
- ./downloads:/downloads
depends_on:
gluetun:
condition: service_healthy
restart: unless-stoppedAng :v3 tag ang pinakabagong stable release sa v3 series. Ang :latest tag ay tumutukoy sa huling commit ng master branch, na development edge; kaya i-pin ang :v3 sa machine na ayaw mong i-debug sa hindi angkop na oras.
Dapat tumugma ang WEBUI_PORT=8080 sa published port, dahil nagbi-bind ang qBittorrent sa loob ng namespace ng gluetun at ipinapasa ng publish rule ang traffic mula sa host sa port 8080 doon. Kapag binago ang isang numero nang hindi binabago ang isa pa, walang sasagot sa port. Pinananatili ng 127.0.0.1:8080:8080 ang web interface sa loopback address ng host. Kapag bare na 8080:8080, ipa-publish nito ang port sa lahat ng interface at gagawa ito ng sarili nitong firewall rule. Ito ang dahilan kung bakit direktang nalalampasan ng Docker published ports ang ufw.
I-start ito, pagkatapos ay suriin sa ganitong pagkakasunod-sunod:
docker compose up -d
docker compose ps
docker compose logs gluetun | tail -30Dapat ipakita ng docker compose ps ang gluetun bilang healthy at ang qbittorrent bilang running. Pagkatapos, kumpirmahin ang exit address mula sa loob ng namespace. Ito ang pagsusuring magpapasya sa lahat ng iba pa:
docker run --rm --network=container:gluetun alpine:3.22 sh -c "apk add wget && wget -qO- https://ipinfo.io"Dapat ang address ng VPN provider mo ang nasa ip field ng JSON na iyon. Kung sariling address ng server mo ang lumabas, wala ang app sa tunnel, kaya hindi gagana ayon sa inilalarawan ang mga sumusunod.
Huwag ilagay ang mga key sa compose file
Ang gluetun.env ang naglalaman ng credentials, at hindi ito isinasama sa git:
WIREGUARD_PRIVATE_KEY=wOEI9rqqbDwnN8/Bpp22sVz48T71vJ4fYmFWujulwUU=
WIREGUARD_ADDRESSES=10.64.222.21/32Galing ang dalawang value sa WireGuard configuration file na ginagawa mo sa account area ng provider mo. Itakda ang file sa mode 600. Maging malinaw sa proteksiyong ibinibigay nito: hindi napupunta ang key sa repository mo, pero inililista pa rin ng docker inspect gluetun ang bawat environment variable sa sinumang makakaabot sa Docker socket. Saklaw ng Mga environment file at secret sa Docker Compose ang mas matibay na mga opsyon.
Paano kumokonekta ang container na nasa labas ng tunnel sa container na nasa loob nito
Gumagana ang parehong direksyon, at magkaibang pangalan ang ginagamit ng bawat isa. Kailangang nasa iisang shared Docker network ang dalawang container. Ito ang network ni gluetun, dahil walang sariling network ang naka-attach na container. Ipinaliliwanag sa Paano nakaayos ang mga Docker Compose network ang mga default.
Mula sa labas papasok, gamitin ang pangalan ni gluetun at ang port na ginagamit ng app sa pakikinig. Maa-access ng reverse proxy container ang web interface ng qBittorrent sa gluetun:8080. Hindi kailangan ang entry na ports: dahil nananatili sa Docker network ang traffic sa pagitan ng mga container at hindi ito dumadaan sa host port.
Mula sa loob palabas, gamitin ang service name ng kabilang container, halimbawa ang postgres:5432. Nareresolba na ni Gluetun ang mga pangalan ng ibang container mula sa loob ng namespace nito simula v3.41. Kaya gumamit ng bersyong iyon o mas bago kung hindi nareresolba ang isang pangalan.
Ang firewall ni Gluetun ang nagpapasya kung sino ang maaaring magbukas ng koneksyon dito. Pinapayagan ang traffic mula sa sariling Docker network ni gluetun. Ibinabagsak ang koneksyon mula sa ibang subnet, gaya ng laptop sa iyong LAN o container sa hiwalay na bridge network, hanggang sa tukuyin mo ang subnet na iyon:
FIREWALL_OUTBOUND_SUBNETS=192.168.1.0/24Eksakto ang dokumentadong kahulugan: mga subnet na pinaghihiwalay ng kuwit na pinapayagang ma-access ng Gluetun at ng mga container na gumagamit ng kaparehong network stack nito.
Hiwalay na problema ang mga inbound connection mula sa internet. Dumarating ang mga peer ng torrent client mula sa panig ng VPN, kaya walang epekto sa kanila ang pag-publish ng port 6881 sa host. Kailangan mo ng forwarded port mula sa iyong provider, at dapat nakalista ang port na iyon sa FIREWALL_VPN_INPUT_PORTS. Pinapayagan nito ang mga port mula sa panig ng VPN server. Ito ang bahaging kadalasang hindi naaayos ng karamihan sa media stack na binuo gamit ang Docker Compose.
Ang kill switch: ano ang nangyayari kapag bumaba ang tunnel
Dito nagiging sulit ang pagiging kumplikado ng setup kapag may failure. Walang pangalawang route ang naka-attach na container. Ang namespace na pinaghahatian nito ang tanging daanan palabas ng machine. Kaya kapag down ang tunnel, wala itong fallback. Ipinapatupad din ng firewall ng Gluetun ang parehong rule mula sa kabilang panig: dumadaan sa tunnel o sa VPN server endpoint ang outbound traffic, at dini-drop ang lahat ng iba pa. Walang pagkakataong lumabas ang mga packet sa plain interface habang muling kumokonekta ang client.
Mino-monitor ng Gluetun ang sarili nitong connection. Bawat minuto, nagpapadala ito ng ICMP echo (ping) sa mga address sa HEALTH_ICMP_TARGET_IPS, na ang default ay 1.1.1.1,8.8.8.8. Bawat limang minuto, nagsasagawa ito ng kumpletong TCP at TLS (transport layer security) dial sa HEALTH_TARGET_ADDRESSES, na ang default ay cloudflare.com:443,github.com:443. Kapag nabigo ang mga ito, nire-restart nito ang VPN sa loob ng container at nila-log ang pangyayari:
WARN [vpn] restarting VPN because it failed to pass the healthcheck: periodic check: dialing: dial tcp4: lookup cloudflare.com: i/o timeoutBasahin ang logs ng naka-attach na container ayon sa pagkakasunod na iyon. Ang mga linyang gaya ng connection refused, operation not permitted, at i/o timeout sa loob ng app ay mga resulta ng patay na tunnel, hindi mga sanhi. Malinaw itong sinasabi sa documentation ng Gluetun dahil iniuulat ng mga tao ang resulta at ilang oras nilang hinahabol ang maling problema.
Ang HEALTH_RESTART_VPN=on ang default at dapat manatiling naka-on. I-off lamang ito habang dine-debug ang isang partikular na failure, dahil kapag naka-off ito, mananatiling patay ang tunnel kapag bumagsak ito.
Pagkakasunod-sunod: huwag simulan ang stack bago umandar ang tunnel
May Docker healthcheck ang image:
HEALTHCHECK --interval=5s --timeout=5s --start-period=10s --retries=1 CMD /gluetun-entrypoint healthcheckNagpapatakbo ang command na iyon ng isa pang panandaliang kopya ng gluetun na kumokonekta sa health server ng kasalukuyang instance sa http://127.0.0.1:9999/. Sumasagot ang gumaganang tunnel ng 200 OK. Sumasagot naman ang sirang tunnel ng 500 Internal server error na may error string, at minamarkahan ang container bilang unhealthy pagkatapos ng isang failure.
Ang condition: service_healthy ang naghihintay para rito. Ang karaniwang depends_on: [gluetun] ay naghihintay lamang na magsimula ang container. Nangyayari iyon ilang segundo bago makumpleto ang handshake, kaya nagsisimula ang app habang walang gumaganang network at madalas nitong hindi natatapos ang unang connection attempt. Tinalakay sa Healthchecks sa Docker Compose ang syntax at mga timing field.
May isang limitasyon na madalas nakalilito. Isang beses lamang sinusuri ng Compose ang condition na iyon, kapag ginagawa nito ang container. Hindi nito ihihinto o ire-restart ang app kapag naging unhealthy ang gluetun. Sa halip, saklaw ito ng internal auto-healing ng gluetun. Ito ang dahilan kung bakit nire-restart nito ang VPN process, hindi ang container.
Suriin ang DNS leak bago pagkatiwalaan ang setup
Ang DNS (domain name system) ang leak na nananatili kahit tama ang tunnel. Gumagamit ang Gluetun ng sarili nitong resolver sa loob ng namespace at ipinapasa nito ang mga query sa Cloudflare gamit ang DoT (DNS over TLS) bilang default: DNS_UPSTREAM_RESOLVER_TYPE=dot at DNS_UPSTREAM_RESOLVERS=cloudflare. Huwag baguhin ang mga ito upang manatiling encrypted ang iyong lookups at dumaan sa tunnel.
Ang setting na sumisira rito ay DNS_UPSTREAM_PLAIN_ADDRESSES. Ginagamit ito kapag hindi ma-resolve ang isang pangalan at nais nilang router o resolver ng provider ang sumagot. Malinaw ang babala ng Gluetun documentation tungkol sa kapalit: hindi dadaan sa VPN tunnel ang lahat ng DNS traffic at magle-leak ito palabas. Mananatiling private ang iyong traffic. Hindi ganoon ang listahan ng mga hostname na iyong ina-access. Tinalakay ang katumbas na pagkakamali sa WireGuard sa DNS na hindi na nagre-resolve sa WireGuard tunnel.
Para subukan ito, itakda ang HTTPPROXY=on sa gluetun at i-publish ang 8888:8888/tcp, pagkatapos ay ituro ang browser sa proxy na iyon at mag-load ng DNS leak test. Dapat lumabas sa resulta ang pangalan ng iyong provider o Cloudflare, at hindi kailanman ang iyong home router. Nagbababala ang sariling documentation ng Gluetun na maaaring magpakita ng kakaibang resulta ang ilang leak test dahil ang resolver sa loob ng namespace ay lokal na caching intermediary, hindi ang server na sa huli ay sumasagot. Ituring na totoong senyales ang maling bansa o ang resolver ng sarili mong ISP.
Pagdaragdag ng Tailscale sa tabi ng VPN sidecar, at kung alin ang mananaig
Ang Tailscale ay isang overlay network na binuo sa WireGuard para ma-access ang sarili mong mga machine. Ginagamit ito ng ilan kasabay ng provider VPN upang manatiling may admin path papunta sa stack. Bihirang magkasalungat ang dalawa dahil may mahalagang dahilan. Ayon sa documentation ng Tailscale, ito ang default: kumikilos ito bilang overlay network, nagra-route lamang ito ng traffic sa pagitan ng mga device na nagpapatakbo ng Tailscale, at hindi nito hinahawakan ang public internet traffic mo.
Depende ang sagot sa isang setting.
- Tailscale sa sarili nitong container, default configuration: hindi nito kailanman nakikita ang outbound traffic ng app. Gluetun ang nagdadala ng lahat ng traffic na ito. Ina-access ng Tailscale ang app sa
gluetun:8080, gaya ng ibang external container. - Naka-attach ang Tailscale sa namespace ng gluetun gamit ang
network_mode: "service:gluetun": kailangan nito ng sarili nitongcap_addngnet_adminatnet_rawdahil hindi awtomatikong kasama sa namespace ang capabilities. Sa default userspace networking mode, naka-enable angTS_USERSPACE. Walang interface na ginagawa ang tailscaled at gumagana ito bilang SOCKS5 o HTTP proxy, kaya hindi nito mababago ang routing. Gluetun pa rin ang nagdadala ng lahat ng traffic. - Pareho pa rin ito kapag ginagamit ang
TS_USERSPACE=false: gumagawa ang tailscaled ng tunnel device at nag-i-install ng routes, pero para lamang sa tailnet range na100.64.0.0/10at sa anumang subnet routes na ina-advertise mo gamit angTS_ROUTES. Dumadaan pa rin sa gluetun ang public traffic. - Anuman sa mga configuration sa itaas kapag may napiling exit node,
sudo tailscale set --exit-node=<exit-node-ip>: inaangkin ng Tailscale ang default route at ito ang mananaig. Huwag itong pagsamahin sa gluetun. Isang default route, isang may-ari.
Kung ang mga ina-advertise na route ang kailangan mo, at gusto mong ma-access ang buong private network sa likod ng box sa halip na ang box lamang, ipinapaliwanag ng pagpapatakbo ng Tailscale subnet router sa isang VPS ang route approval, IP forwarding, at client-side flag na hindi awtomatikong ginagawa ng TS_ROUTES.
Kung ang layunin ng Tailscale ay bigyan ka ng admin URL sa halip na route, inilalagay ng tailscale serve at tailscale funnel ang HTTPS sa harap ng gluetun:8080 para sa tailnet mo. Ang funnel lamang ang nagbubukas nito sa public internet.
Makikita ang isang epekto kapag tumatakbo ang Tailscale sa loob ng tunnel. Nakikita ng mga peer nito ang address ng VPN provider, kaya mas madalas itong umaasa sa mga relay. Ipinapakita ng tailscale status ang relay "..." sa tabi ng isang peer sa halip na direct kapag nangyari ito. Gumagana ang koneksyon, pero mas mabagal ito. Kung overlay lamang ang talagang kailangan mo, mas magandang panimulang punto ang pagkakaiba ng plain WireGuard at Tailscale.
Mga pumapalya, at ang mensaheng makikita mo
Tumangging gumawa ang Docker ng app container. Ibig sabihin ng Error response from daemon: conflicting options: port publishing and the container type network mode na may ports: block pa ring nakakabit sa service. Ilipat ito sa gluetun.
Tumanggi ang Compose sa buong file. Hindi maaaring magtakda ang isang service ng parehong network_mode at networks. Ilagay ang mga network sa gluetun.
Hindi ma-resolve ng ibang container ang app. Tamang behavior ang curl: (6) Could not resolve host: qbittorrent dahil walang network na sinalihan ang nakakabit na container at wala itong nirehistrong pangalan. Gamitin ang gluetun at ang port.
Hindi nagsisimula ang ikalawang nakakabit na container. Hindi maaaring mag-bind ang dalawang proseso sa iisang namespace sa parehong port. Magrereport ang hindi nakakuha ng port na ginagamit na ang address. Palitan ang internal port ng app, o magpatakbo ng ikalawang gluetun.
Wala nang network ang app matapos mong baguhin ang gluetun. Kapag ni-restart o ni-recreate ang gluetun, nawawala ang connectivity ng lahat ng nakakabit dito. I-restart ang mga container na iyon.
Mabilis mag-load ang maliliit na page pero nagha-hang ang malalaki. MTU (maximum transmission unit) ang sanhi nito. Nagdaragdag ng overhead ang tunnel, at may bahagi ng path na nagtatapon ng sobrang laking packet nang hindi nagpapadala ng error. Ibaba ang WIREGUARD_MTU, subukan ang 1400, pagkatapos ay ang 1320.
Hindi kailanman nagiging healthy ang Gluetun. Tinutukoy ng startup check ang mga unang dapat siyasatin: WARN [vpn] restarting VPN because it failed to pass the healthcheck: startup check: dialing: dial tcp4: lookup cloudflare.com: i/o timeout. Tingnan kung nag-expire na ang key, pagkatapos ay kung luma na ang server list, at pagkatapos ay kung bina-block ng host firewall ang outbound UDP.
FAQ
Bakit hindi na gumagana ang mga published port ng container ko kapag nasa likod ito ng Gluetun?
Dahil inilalagay ng network_mode: "service:gluetun" ang container sa network namespace ng gluetun, at ang isang namespace ay may isang IP address at isang set ng listening port. Patuloy na nakikinig ang app, pero kailangang nasa container na nagmamay-ari ng namespace ang publish rule. Ilipat ang listahan ng ports: sa gluetun service. Kung iniwan mo ito sa attached service, hindi man lang ito gagawin ng Docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
Paano ko maa-access mula sa container na nasa labas ng VPN tunnel ang container na nasa loob nito?
Gamitin ang service name ng gluetun at ang port na ginagamit ng app, halimbawa gluetun:8080. Walang sariling Docker network ang attached container, kaya hindi kailanman mare-resolve ang sarili nitong pangalan. Walang kailangang i-publish para sa container-to-container traffic. Sa kabilang direksyon, maa-access ng container na nasa loob ng namespace ang container na nasa labas gamit ang service name nito, gaya ng postgres:5432, sa Gluetun v3.41 at mas bago. Ibinabagsak ng gluetun firewall ang client mula sa ibang subnet, gaya ng laptop sa iyong LAN, hanggang idagdag mo ang subnet na iyon sa FIREWALL_OUTBOUND_SUBNETS.
Gumagana ba ang Gluetun bilang kill switch kapag bumagsak ang VPN?
Oo, at dalawang dahilan ang sabay na gumagana. Walang ibang route ang attached container maliban sa route sa shared namespace, kaya kapag patay ang tunnel, wala itong path palabas ng machine. Pinapahintulutan din ng firewall ng Gluetun ang outbound traffic lamang sa tunnel at sa VPN server endpoint. Sa halip na mag-exit, nire-restart ng Gluetun ang VPN internally at nilala-log ang WARN [vpn] restarting VPN because it failed to pass the healthcheck, dahil mawawalan ng network ang bawat attached container kapag mismong gluetun ang nag-restart.
Tailscale at Gluetun sa iisang stack: alin ang nagdadala ng outbound traffic?
Gluetun, maliban sa isang configuration. Bilang default, niruruta lamang ng Tailscale ang traffic sa pagitan ng mga device sa iyong tailnet at hindi nito ginagalaw ang public traffic. Sa default userspace mode ng container image, wala itong ginagawang interface, kaya hindi nito maaapektuhan ang routing. Kapag ginamit ang TS_USERSPACE=false, nag-i-install ito ng mga route para lamang sa 100.64.0.0/10 at sa iyong advertised subnet. Ang exception ay isang exit node: ginagawa ng sudo tailscale set --exit-node=<exit-node-ip> na default route ang Tailscale, kaya ito ang mananaig. Pumili ng isang product na mamamahala sa default route sa halip na pagsabayin ang dalawa.