SSD Nodes Learn 🎉 VPS $4.99/माह से
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-07

Gluetun container से host और अन्य services कैसे जोड़ें

Gluetun के साथ जुड़े container का अपना network interface नहीं होता है। इस गाइड में जानें कि कैसे आप Gluetun पर ports publish करें और केवल आवश्यक subnets के लिए access खोलें।

जब कोई container gluetun के network से जुड़ता है तो क्या होता है

जो container network_mode: service:gluetun सेट करता है, उसका अपना कोई network interface नहीं होता। वह gluetun के network namespace में शामिल हो जाता है, इसलिए port publishing और firewall rules उस container की विशेषता न रहकर gluetun service की विशेषता बन जाते हैं। नीचे दिया गया हर उत्तर इसी एक तथ्य पर आधारित है।

Network namespace, kernel के network stack की एक निजी प्रति (copy) होती है: इसके अपने interfaces, अपनी routing table, अपने firewall rules और अपने listening sockets होते हैं। Docker डिफ़ॉल्ट रूप से प्रत्येक container को एक namespace देता है। जब आप network_mode: service:gluetun लिखते हैं, तो Docker उस चरण को छोड़ देता है और नए container को उस namespace के अंदर डाल देता है जिसे gluetun पहले से नियंत्रित करता है। container का अपना filesystem और अपनी /etc/hosts फ़ाइल बनी रहती है, और यह दूसरी वाली फ़ाइल बाद में महत्वपूर्ण हो जाती है।

आप इसे सीधे देख सकते हैं।

docker inspect -f '{{.HostConfig.NetworkMode}}' qbittorrent

यह container: के बाद gluetun container ID प्रिंट करता है, जबकि एक सामान्य container bridge प्रिंट करेगा। यह गाइड वहीं से शुरू होती है जहाँ gluetun के साथ VPN के माध्यम से Docker traffic को route करना समाप्त होती है: tunnel काम कर रही है, और अब container से कोई भी संपर्क नहीं कर सकता।

Port को application पर नहीं, gluetun पर publish करें

service पर एक ports: block छोड़ दें जो network_mode सेट करता है, तो Docker container बनाने से मना कर देगा:

Error response from daemon: conflicting options: port publishing and the container type network mode

इसका कारण सीधा है। Port publish करने का अर्थ है एक NAT (network address translation) rule जोड़ना, जो host port को container के अपने network namespace में forward करता है, और इस container के पास अपना namespace नहीं होता। Mapping को gluetun service पर ले जाएँ। Port number नहीं बदलता, क्योंकि application अभी भी shared namespace के अंदर उसी port पर listen कर रही है।

services:
  gluetun:
    ports:
      - "8080:8080/tcp"   # qBittorrent web UI

  qbittorrent:
    network_mode: "service:gluetun"
    # no ports: block here

Dependent service पर एक expose: block भी उतना ही निरर्थक है, और वहाँ एक networks: block एक hard stop है: Compose रिपोर्ट करता है कि service परस्पर विरोधी network_mode और networks घोषित करती है, और file को load करने से पूरी तरह मना कर देती है।

इसका एक परिणाम बाद में सामने आता है। Namespace में प्रत्येक container एक ही port space साझा करता है, इसलिए दो applications जो दोनों default रूप से 8080 पर चलती हैं, आपस में टकराती हैं, और दूसरी application जो start होती है, वह address already in use error के साथ fail हो जाती है। उनमें से एक को उसकी अपनी configuration में बदलें, उदाहरण के लिए LinuxServer qBittorrent image पर WEBUI_PORT variable, और फिर gluetun पर नया number publish करें।

gluetun के पीछे मौजूद containers एक-दूसरे तक कैसे पहुँचते हैं?

namespace के भीतर वे पहले से ही एक loopback interface साझा करते हैं। gluetun के पीछे मौजूद एक container अपने sibling तक 127.0.0.1:<port> पर पहुँचता है, जिसमें किसी Docker network की आवश्यकता नहीं होती।

namespace के बाहर से, container का कोई नाम नहीं होता। Docker का embedded DNS एक service name को user-defined network पर उस service के address में resolve करता है, और इस container का किसी भी network पर कोई address नहीं होता। इसलिए Sonarr जैसा एक सामान्य container torrent client तक http://qbittorrent:8080 पर नहीं पहुँचता। यह उस तक http://gluetun:8080 पर पहुँचता है, क्योंकि socket gluetun के namespace में, gluetun के address पर listen कर रहा होता है। यह उन लोगों को आश्चर्यचकित करता है जो Docker Compose networks और service names कैसे काम करते हैं जानते हैं और सामान्य naming लागू होने की अपेक्षा रखते हैं। यह host पर कुछ भी publish किए बिना भी काम करता है, क्योंकि दोनों containers एक ही Compose network पर होते हैं।

किसी और चीज़ को debug करने से पहले DNS की जाँच करें। gluetun अपना खुद का resolver चलाता है और अपने container में /etc/resolv.conf को rewrite करता है, लेकिन /etc/resolv.conf प्रति container एक file होती है, इसलिए जो gluetun ने लिखी है वह वह नहीं है जिसे आपका application पढ़ता है।

docker exec qbittorrent cat /etc/resolv.conf

Docker host पर चल रही service तक कैसे पहुँचें?

इसके लिए host.docker.internal का उपयोग करें। इसमें दो अलग-अलग जगहों पर दो सेटिंग्स करनी होती हैं, क्योंकि दो अलग-अलग चीजें काम नहीं कर रही होती हैं।

नाम सबसे पहले आता है। /etc/hosts प्रति container होता है, इसलिए extra_hosts एंट्री gluetun पर नहीं, बल्कि application container पर होनी चाहिए।

  prowlarr:
    network_mode: "service:gluetun"
    extra_hosts:
      - "host.docker.internal:host-gateway"

host-gateway एक विशेष मान है जिसे Docker host के आंतरिक पते (internal address) से बदल देता है। एक सामान्य Linux Docker install पर यह docker0 bridge का पता होता है, जो आमतौर पर 172.17.0.1 होता है। VPS पर ip -4 addr show docker0 चलाकर इसकी पुष्टि करें। Docker Desktop इस नाम को अपने आप resolve कर लेता है, इसीलिए laptop पर लिखे गए guides में extra_hosts लाइन को छोड़ दिया जाता है और वही फाइल server पर काम नहीं करती है।

route दूसरे स्थान पर आता है। केवल नाम जोड़ने से container को यह पता चलता है कि किस पते का उपयोग करना है। packet अभी भी gluetun के default route से बाहर निकलता है, जो कि tunnel है, और gluetun का firewall उसे drop कर देता है। इसका लक्षण यह है कि connection hang हो जाता है और फिर time out हो जाता है, न कि connection refuse होता है। refusal का मतलब है कि packet पहुँच गया और किसी ने 'नहीं' में जवाब दिया। timeout का मतलब है कि वह कभी पहुँचा ही नहीं।

  gluetun:
    environment:
      - FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32

इसके बाद जाँचें कि host service वास्तव में उस पते पर listen कर रही है या नहीं। केवल 127.0.0.1 पर bound PostgreSQL server किसी भी container से पहुँच योग्य नहीं होता, चाहे tunnel हो या न हो, क्योंकि namespace के अंदर 127.0.0.1 उस namespace का अपना loopback होता है। इसे इसके बजाय 172.17.0.1 पर bind करें: यह public interface से दूर रहते हुए containers से connections स्वीकार करता है। host पर ss -lntp | grep 5432 के साथ इसकी पुष्टि करें।

FIREWALL_OUTBOUND_SUBNETS वास्तव में क्या बदलता है

gluetun का documentation इसे उन comma-separated subnets के रूप में वर्णित करता है जिन्हें gluetun और इसके network stack को साझा करने वाले containers एक्सेस कर सकते हैं। यह ध्यान दें कि इसमें firewall और routing दोनों में बदलाव शामिल हैं। दोनों हिस्से महत्वपूर्ण हैं। Gluetun सूचीबद्ध प्रत्येक subnet के लिए Docker bridge gateway के माध्यम से एक route जोड़ता है, ताकि उन addresses के लिए packets tunnel के बजाय eth0 पर बाहर निकलें। यह उनके लिए firewall भी खोलता है, क्योंकि अन्यथा gluetun उन outbound traffic को drop कर देता है जो VPN server के लिए नहीं होते।

value को commas के बाद बिना किसी space के लिखें।

      - FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32,192.168.1.0/24,100.64.7.9/32

दो गुणों को नजरअंदाज करना आसान है। यह एक namespace level की setting है, इसलिए यह केवल आपके द्वारा सोचे गए container पर ही नहीं, बल्कि gluetun के पीछे के हर container पर लागू होती है। और यह केवल outbound है: यह उन connections को नियंत्रित करती है जिन्हें एक container शुरू करता है। published port पर आने वाले connections एक अलग रास्ते से आते हैं और उन्हें यहाँ किसी entry की आवश्यकता नहीं होती है।

Tailscale peer से web UI तक पहुँचना

Tailscale हर मशीन को 100.64.0.0/10 में एक पता देता है, जो carrier grade NAT के लिए आरक्षित रेंज है। दोनों दिशाओं के लिए अलग-अलग कार्य करने की आवश्यकता होती है।

Inbound (आने वाला traffic) सरल है। gluetun पर 8080:8080 को publish करने से वह port host के सभी पतों पर bind हो जाता है, और host का tailscale0 interface उनमें से एक है, इसलिए एक peer http://<machine-name>:8080 खोलता है और container तक पहुँच जाता है। उस path में Gluetun की कोई भूमिका नहीं होती, क्योंकि Docker का NAT rule host पर, namespace के बाहर स्थित होता है।

UI को केवल tailnet के माध्यम से ही सुलभ बनाने के लिए, published port को हर पते के बजाय host के Tailscale पते पर bind करें।

    ports:
      - "100.101.102.103:8080:8080/tcp"

उस पते को host पर tailscale ip -4 के साथ ढूँढें। यहाँ binding एक firewall rule की तुलना में अधिक मजबूत नियंत्रण है, क्योंकि port public interface पर कभी खुलता ही नहीं है। यह Docker द्वारा सीधे ufw के पार ports publish करने की समस्या से भी बचाता है।

Outbound (बाहर जाने वाला traffic) वह जगह है जहाँ FIREWALL_OUTBOUND_SUBNETS वापस आता है। यदि किसी container को किसी peer को call करना है, तो उस peer का पता जोड़ें, और पूरे /10 के बजाय प्रति peer एक /32 को प्राथमिकता दें। MagicDNS नाम container के अंदर resolve नहीं होंगे, क्योंकि container host के resolver का उपयोग नहीं करता है, इसलिए संख्यात्मक 100.x पते का उपयोग करें या इसे extra_hosts line के साथ pin करें। यही बात तब भी लागू होती है जब आप Headscale के साथ अपना खुद का Tailscale control server चलाते हैं।

सामान्य संरचना के लिए एक पूर्ण compose फ़ाइल

VPN के पीछे एक डाउनलोड क्लाइंट, केवल tailnet पर प्रतिक्रिया देने वाले दो वेब UI, और एक कंटेनर जो होस्ट पर चल रहे PostgreSQL डेटाबेस को पढ़ता है।

services:
  gluetun:
    image: qmcgaw/gluetun:latest
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - "127.0.0.1:8000:8000/tcp"        # gluetun control server, host only
      - "100.101.102.103:8080:8080/tcp"  # qBittorrent UI, tailnet only
      - "100.101.102.103:9696:9696/tcp"  # Prowlarr UI, tailnet only
    volumes:
      - ./gluetun:/gluetun
    environment:
      - VPN_SERVICE_PROVIDER=mullvad
      - VPN_TYPE=wireguard
      - WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
      - WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
      - SERVER_CITIES=Amsterdam
      - FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32,100.64.7.9/32
      - TZ=Europe/Amsterdam
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    network_mode: "service:gluetun"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Amsterdam
      - WEBUI_PORT=8080
    volumes:
      - ./qbittorrent:/config
      - /srv/downloads:/downloads
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    network_mode: "service:gluetun"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Amsterdam
      - PROWLARR__POSTGRES__HOST=host.docker.internal
      - PROWLARR__POSTGRES__PORT=5432
      - PROWLARR__POSTGRES__USER=prowlarr
      - PROWLARR__POSTGRES__PASSWORD=${PROWLARR_DB_PASSWORD}
      - PROWLARR__POSTGRES__MAINDB=prowlarr-main
      - PROWLARR__POSTGRES__LOGDB=prowlarr-log
    volumes:
      - ./prowlarr:/config
    depends_on:
      gluetun:
        condition: service_healthy
    restart: unless-stopped

उत्पाद के नामों के बजाय पैटर्न के लिए फ़ाइल को पढ़ें। दोनों UI gluetun पर पब्लिश किए गए हैं और होस्ट के tailnet पते से बंधे हैं, इसलिए वे केवल Tailscale पर प्रतिक्रिया देते हैं और कहीं और नहीं। केवल Prowlarr में extra_hosts लाइन है, क्योंकि Prowlarr वह कंटेनर है जो host.docker.internal को रिज़ॉल्व करता है। FIREWALL_OUTBOUND_SUBNETS दो एकल पतों को नामित करता है: होस्ट का Docker ब्रिज पता, ताकि Prowlarr डेटाबेस कनेक्शन खोल सके, और एक tailnet पीयर।

PostgreSQL सर्वर जानबूझकर फ़ाइल से बाहर रखा गया है। यह VPS पर एक सामान्य सिस्टम सर्विस के रूप में चलता है जो 172.17.0.1:5432 पर लिसन करता है। यह Docker Compose पर एक arr स्टैक के समान लेयरिंग है, जिसमें डेटाबेस को Docker के बाहर रखा गया है।

WireGuard प्राइवेट की को compose फ़ाइल से बाहर रखें। ${WIREGUARD_PRIVATE_KEY} अपने बगल में स्थित एक .env फ़ाइल से पढ़ता है, यह पैटर्न Docker Compose के लिए env फ़ाइलें और सीक्रेट्स में कवर किया गया है। condition: service_healthy क्लॉज उस हेल्थचेक का उपयोग करता है जो gluetun इमेज में पहले से ही मौजूद है, इसलिए जब तक टनल चालू होने की रिपोर्ट नहीं देती, तब तक कुछ भी शुरू नहीं होता है। Compose हेल्थचेक्स सामान्य रूप की व्याख्या करते हैं।

केवल tailnet के बजाय हर पते पर पब्लिश करना

0.0.0.0 पर एड्रेस प्रीफ़िक्स और पोर्ट बाइंड्स को हटा दें, जिसमें VPS का पब्लिक IP शामिल है। ऐसा केवल उस फ़ायरवॉल के पीछे करें जिसे आप नियंत्रित करते हैं, और पहले ऊपर दिए गए ufw नोट को पढ़ें।

    ports:
      - "8080:8080/tcp"

सुनिश्चित करें कि टनल अभी भी ट्रैफिक ले जा रही है

एक ही request को दो बार चलाएं, एक बार namespace के अंदर से और एक बार host से, और तुलना करें।

docker run --rm --network=container:gluetun curlimages/curl:latest -s https://api.ipify.org
curl -s https://api.ipify.org

पहली request को आपके VPN प्रदाता का exit address दिखाना चाहिए। दूसरी को VPS का address दिखाना चाहिए। यदि वे मेल खाते हैं, तो container का ट्रैफिक टनल से होकर नहीं जा रहा है, और इस गाइड का कोई भी सुधार तब तक व्यर्थ है जब तक इसे ठीक नहीं किया जाता।

Routing table दिखाती है कि क्या टनल से बाहर है और क्या नहीं।

docker run --rm --network=container:gluetun alpine:3.22 ip route show

Default route को टनल इंटरफ़ेस, tun0 की ओर इशारा करना चाहिए। इसके नीचे आपको FIREWALL_OUTBOUND_SUBNETS में प्रत्येक प्रविष्टि के लिए एक route दिखना चाहिए, जो Docker bridge gateway की ओर इशारा करता हो। eth0 के माध्यम से बाहर जाने वाला कोई भी अन्य route वह ट्रैफिक है जो VPN को छोड़ देता है।

Gluetun का control server पोर्ट 8000 पर, /v1/publicip/ip पर वही public IP रिपोर्ट करता है। हाल के संस्करणों में आपको control server routes के लिए authentication कॉन्फ़िगर करने की आवश्यकता होती है, इसलिए उस पर निर्भर होने से पहले उसे सेट अप करें।

गलत subnet बनाने से होने वाला leak

FIREWALL_OUTBOUND_SUBNETS वह छेद है जिसे आप जानबूझकर firewall में करते हैं, इसलिए छेद का आकार ही जोखिम का आकार है। इसे बहुत बड़ा बनाने के चार तरीके:

  • 0.0.0.0/0 सब कुछ tunnel के बाहर भेज देता है। ऊपर दिए गए दो IP checks इसे पहली बार में ही पकड़ लेते हैं, क्योंकि वे एक ही address लौटाएंगे।
  • target से बड़ा range। केवल 10.0.1.7 पर स्थित एक machine तक पहुँचने के लिए 10.0.0.0/8 खोलना उन सभी addresses को भी खोल देता है जिन्हें कोई torrent peer उस range में advertise कर सकता है। 10.0.1.7/32 लिखें।
  • ऐसा range जो tunnel के अपने addresses के साथ overlap करता हो। gluetun documentation चेतावनी देता है कि इससे gluetun, VPN traffic को bridge के माध्यम से बाहर भेज देता है, जिससे port forwarding टूट जाती है। कोई भी private range खोलने से पहले अपना WIREGUARD_ADDRESSES मान जाँचें।
  • Tailscale के लिए 100.64.0.0/10। यह लगभग चालीस लाख addresses खोल देता है ताकि एक peer तक पहुँचा जा सके। जिन peers की आपको आवश्यकता है, उन्हें /32 entries के रूप में सूचीबद्ध करें।

याद रखें कि यह setting पूरे namespace को कवर करती है। किसी subnet को इसलिए खोलना कि एक indexer किसी host service तक पहुँच सके, उसी subnet को उस namespace में share करने वाले torrent client के लिए भी खोल देता है। इस variable में हर बदलाव के बाद public IP check को फिर से चलाएँ, क्योंकि यही एकमात्र परीक्षण है जो यह दिखाता है कि बदलाव ने वही किया है जो आप चाहते थे।

gluetun को restart करने पर क्या खराब होता है

gluetun ही namespace का स्वामी होता है, इसलिए namespace का जीवनचक्र gluetun के जीवनचक्र पर निर्भर करता है। gluetun के बंद होने पर किसी आश्रित (dependent) container को start करने का प्रयास तुरंत विफल हो जाता है:

Error response from daemon: cannot join network of a non running container

gluetun को उसी स्थान पर restart करना एक शांत विफलता (quieter failure) है। आश्रित containers चलते रहते हैं जबकि जिस namespace से वे जुड़े थे, उसे उनके नीचे से ही फिर से बनाया (rebuild) जा रहा होता है। इस कारण docker ps सब कुछ सही होने की रिपोर्ट देता है, लेकिन कोई भी सेवा प्रतिक्रिया नहीं देती है। gluetun service में किसी भी बदलाव के बाद, केवल एक हिस्से को restart करने के बजाय पूरे group को फिर से बनाएँ (recreate करें)।

docker compose up -d --force-recreate

यही नियम image updates पर भी लागू होता है। gluetun की नई image pull करना और केवल उस एक service को recreate करने से बाकी containers एक ऐसे namespace की ओर संकेत करते हैं जो अब अस्तित्व में नहीं है।

FAQ

Docker "port publishing and the container type network mode" क्यों कहता है?

ऐसा इसलिए है क्योंकि एक ports: ब्लॉक अभी भी उस सर्विस पर है जो network_mode: service:gluetun को भी सेट करती है। पोर्ट पब्लिश करने से एक NAT नियम जुड़ जाता है जो होस्ट पोर्ट को कंटेनर के अपने नेटवर्क नेमस्पेस में फॉरवर्ड करता है, और इस मोड में कंटेनर के पास अपना नेमस्पेस नहीं होता है। उस सर्विस से ports: ब्लॉक को हटा दें और वही मैपिंग gluetun सर्विस में जोड़ दें। पोर्ट नंबर वही रहेगा, क्योंकि एप्लिकेशन अभी भी साझा नेमस्पेस के अंदर उसी पर लिसन कर रही है।

अन्य कंटेनर gluetun के पीछे स्थित सर्विस तक कैसे पहुँचते हैं?

एक ही नेमस्पेस के अंदर के कंटेनर एक-दूसरे तक 127.0.0.1 पर पहुँचते हैं। इसके बाहर के कंटेनर gluetun सर्विस नाम का उपयोग करते हैं, इसलिए http://gluetun:8080 काम करता है जहाँ http://qbittorrent:8080 नहीं करता। एप्लिकेशन कंटेनर के पास किसी भी Docker नेटवर्क पर कोई एड्रेस नहीं होता है, इसलिए एम्बेडेड DNS सर्वर के पास उसके नाम के लिए रिजॉल्व करने हेतु कुछ नहीं होता है। इसके लिए किसी पोर्ट पब्लिशिंग की आवश्यकता नहीं है, बशर्ते दोनों कंटेनर एक ही Compose नेटवर्क साझा करते हों।

मुझे FIREWALL_OUTBOUND_SUBNETS में क्या डालना चाहिए?

केवल वे एड्रेस जिन्हें gluetun के पीछे के कंटेनर को कनेक्शन शुरू करने के लिए आवश्यक है, उन्हें जितना संभव हो उतना संकीर्ण (narrowly) लिखें। एक सिंगल मशीन एक /32 है। दो सामान्य प्रविष्टियाँ 172.17.0.1/32 पर Docker होस्ट और आपके द्वारा कॉल किए जाने वाले प्रत्येक Tailscale पीयर के लिए एक /32 हैं। कभी भी 0.0.0.0/0 न जोड़ें, और कभी भी ऐसी रेंज न जोड़ें जो आपके VPN के अपने टनल एड्रेस के साथ ओवरलैप होती हो। पब्लिश किए गए पोर्ट पर आने वाले इनबाउंड कनेक्शन के लिए यहाँ किसी प्रविष्टि की आवश्यकता नहीं है।

कंटेनर मेरे Tailscale MagicDNS नामों को रिजॉल्व क्यों नहीं कर पा रहा है?

MagicDNS होस्ट के रिजॉल्वर को Tailscale के DNS सर्वर की ओर पॉइंट करके काम करता है, और कंटेनर होस्ट के रिजॉल्वर का उपयोग नहीं करता है। यह उसका उपयोग करता है जो इसका अपना /etc/resolv.conf कहता है, जो gluetun के पीछे gluetun का DNS सेटअप है। docker exec <container> cat /etc/resolv.conf के साथ पुष्टि करें। पीयर के संख्यात्मक 100.x एड्रेस का उपयोग करें, या उस कंटेनर पर extra_hosts प्रविष्टि के साथ नाम को पिन करें।

मैं यह कैसे पुष्टि करूँ कि ट्रैफिक अभी भी VPN के माध्यम से जा रहा है?

नेमस्पेस के अंदर से एक रिक्वेस्ट और होस्ट से वही रिक्वेस्ट चलाएँ, फिर उत्तरों की तुलना करें। docker run --rm --network=container:gluetun curlimages/curl:latest -s https://api.ipify.org को आपके VPN प्रदाता का एग्जिट एड्रेस लौटाना चाहिए, जबकि VPS पर curl -s https://api.ipify.org को VPS का एड्रेस लौटाना चाहिए। दो मेल खाते उत्तरों का मतलब है कि टनल कंटेनर के ट्रैफिक को नहीं ले जा रही है। FIREWALL_OUTBOUND_SUBNETS में हर बदलाव के बाद इस जाँच को फिर से चलाएँ।