SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-07

Docker Compose networking: DNS، host mode اور UFW

Compose کا default bridge، service name سے DNS، host mode کا درست استعمال، projects کے درمیان مشترک network، اور وہ published port جو UFW کو bypass کرتا ہے۔

آپ کی ایپ شروع ہونے سے پہلے Compose کیا بناتا ہے

Docker Compose کی networking ایک اصول سے شروع ہوتی ہے: docker compose up پروجیکٹ کے لیے private network بناتا ہے، ہر service کو اس سے attach کرتا ہے، اور ان services کو service name کے ذریعے ایک دوسرے تک پہنچنے دیتا ہے۔ اس کے لیے آپ کو ایک بھی networks: لائن لکھنے کی ضرورت نہیں ہوتی۔ Compose networking سے متعلق زیادہ تر الجھن اس بات سے پیدا ہوتی ہے کہ default network پہلے ہی موجود ہوتا ہے۔

یہ ایک چھوٹی فائل ہے۔ اسے shop نام کی directory میں compose.yaml کے طور پر محفوظ کریں۔

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

اسے start کریں اور دیکھیں کہ Docker نے کیا بنایا:

docker compose up -d
docker network ls

اب فہرست میں shop_default نام کا network موجود ہے۔ Compose اسے <project>_default نام دیتا ہے، اور project name بطور default directory name کو lowercase میں استعمال کرتا ہے۔ اسے docker compose -p myproject up -d یا فائل میں top-level name: myproject کے ذریعے override کریں۔ اس کا driver bridge ہے، جو host کے اندر ایک virtual switch ہوتا ہے۔ ہر container کو private subnet پر ایک address ملتا ہے، اور باہر جانے والی network traffic کو راستے میں host کے address میں translate کیا جاتا ہے۔

docker compose down اس network کو دوبارہ delete کر دیتا ہے۔ اسی وجہ سے کسی پرانے project کا stale container network کو برقرار رکھ سکتا ہے: Docker error while removing network: network shop_default has active endpoints کے ساتھ انکار کرتا ہے، اور حل یہ ہے کہ اس network سے ابھی تک attached container کو stop یا remove کر دیں۔

اگر Compose آپ کے لیے نیا ہے تو Compose فائل کی ساخت اور lifecycle commands پہلے پڑھ لینا مفید ہے، کیونکہ ذیل کے تمام حصے اس بات کو فرض کرتے ہیں کہ آپ project کو start اور stop کر سکتے ہیں۔

سروس کے نام سے DNS وہ حصہ ہے جسے ابتدائی صارفین نظر انداز کر دیتے ہیں

ہر user-defined network پر Docker ایک embedded DNS server چلاتا ہے، جسے ہر container 127.0.0.11 پر دیکھتا ہے۔ یہ service names کو موجودہ container addresses میں resolve کرتا ہے۔ اس لیے web بغیر کسی configuration کے hostname db پر port 5432 کے ذریعے database تک پہنچ جاتا ہے۔

docker compose exec web getent hosts db

یہ 172.18.0.2 db جیسی line دکھاتا ہے۔ اگر کچھ بھی ظاہر نہ ہو تو دونوں services ایک ہی network پر نہیں ہیں۔

ایک عام غلطی یہ ہے کہ application config میں localhost استعمال کیا جاتا ہے۔ کسی container کے اندر localhost اسی container کو ظاہر کرتا ہے، نہ کہ host یا دوسری service کو۔ Postgres clients اسے واضح طور پر رپورٹ کرتے ہیں:

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

Connection string postgresql://postgres:example@db:5432/postgres ہونی چاہیے۔ اس میں host کا حصہ service name ہے۔

دو تفصیلات بعد میں وقت بچاتی ہیں۔ Names موجودہ running containers کے مطابق resolve ہوتے ہیں، اس لیے docker compose up -d --scale web=3 ایک name کے ساتھ تین addresses دیتا ہے۔ اگر کوئی client DNS کو ہمیشہ کے لیے cache کرے تو وہ خود کو ایک dead container سے وابستہ کر دے گا۔ دوسری طرف، plain docker run کے ذریعے، --network کے بغیر استعمال ہونے والے legacy bridge network میں name resolution بالکل نہیں ہوتا۔ اسی وجہ سے 2016 میں container links سے متعلق دی گئی ہدایات آپ کے موجودہ مشاہدے سے مطابقت نہیں رکھتیں۔

دو سروسز کو آپس میں connect کرنے کے لیے ports: کی ضرورت نہیں

ports:، host پر container port publish کرتا ہے۔ یہ Docker کے باہر سے آنے والے network traffic کے لیے ہوتا ہے۔ اس کا service-to-service traffic سے کوئی تعلق نہیں، کیونکہ project network پر پوری port range کے ذریعے یہ traffic پہلے ہی کام کرتا ہے۔

لہٰذا database service میں بہت سے لوگ جو ports: - "5432:5432" شامل کرتے ہیں، وہ بے فائدہ ہونے کے ساتھ حقیقی نقصان بھی پہنچاتا ہے: یہ server کے public interface پر Postgres کو expose کر دیتا ہے۔ اسے حذف کریں۔ اگر migration کے لیے اسے اپنے laptop سے قابل رسائی بنانا ہو تو "127.0.0.1:5432:5432" کے ذریعے اسے loopback پر bind کریں اور SSH tunnel کے ذریعے access کریں۔ listening socket، published port اور firewall rule کے درمیان فرق Linux پر ports اور listening services کیسے کام کرتی ہیں میں بیان کیا گیا ہے۔

Compose کے تحت expose: صرف documentation ہے۔ یہ کچھ open نہیں کرتا، کیونکہ ایک ہی network پر موجود containers کے درمیان کچھ بھی بند نہیں تھا۔

جب network_mode host درست انتخاب ہو، اور اس کی قیمت کیا ہے

Host mode container کا اپنا network namespace ختم کر دیتا ہے اور process کو host کے interfaces براہِ راست استعمال کرنے دیتا ہے۔

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

اسے استعمال کرنے کی حقیقی وجوہات موجود ہیں۔ مقامی network پر broadcast یا multicast traffic دیکھنے والے process کو اس کی ضرورت ہو سکتی ہے، مثلاً media server یا home automation hub کے لیے device discovery۔ Bridge کے پیچھے موجود container یہ traffic نہیں دیکھ سکتا، کیونکہ bridge اسے container تک forward نہیں کرتا۔ Host کے interface counters پڑھنے والے monitoring agent کو بھی host کے interfaces درکار ہوتے ہیں۔ اس کے علاوہ address translation کا ایک مرحلہ ختم ہو جاتا ہے، جو packet rates زیادہ ہونے پر اہم ہو سکتا ہے۔

اس کے مخصوص نقصانات ہیں۔

ports: کام نہیں کرتا۔ Docker خبردار کرتا ہے کہ host network mode استعمال کرنے پر published ports ختم کر دیے جاتے ہیں، اور container وہی ports bind کرتا ہے جنہیں اس کا process bind کرے۔ اگر host mode کے دو containers port 8080 استعمال کرنا چاہیں تو ان میں تصادم ہوگا، اور دوسرا container bind: address already in use کے ساتھ بند ہو جائے گا۔

Service name کے ذریعے name resolution دونوں سمتوں میں ختم ہو جاتی ہے۔ Container project network پر موجود نہیں ہوتا، اس لیے وہ db کو resolve نہیں کر سکتا، اور دوسری services بھی اسے resolve نہیں کر سکتیں۔ وہ ان services تک صرف host پر published ports کے ذریعے پہنچتا ہے، جو عموماً 127.0.0.1 ہوتے ہیں۔

Isolation ختم ہو جاتی ہے۔ Host mode container کے اندر 0.0.0.0 کو bind کرنے والا process آپ کے server کے ہر interface پر سن رہا ہوتا ہے، بشمول public interface کے، بالکل ایسے جیسے اسے apt سے package کی صورت میں install کیا گیا ہو۔ اس کا ایک فائدہ بھی ہے: یہ traffic معمول کے input path سے گزرتا ہے، اس لیے UFW کے rules اس پر لاگو ہوتے ہیں۔ Published ports کے لیے ایسا نہیں ہوتا۔

Host mode ایک Linux Docker Engine feature ہے۔ Docker Desktop اسے صرف version 4.34 سے سپورٹ کرتا ہے، اور اسے پہلے enable کرنا ضروری ہے۔ مزید یہ کہ containers host IP addresses کو bind نہیں کر سکتے، اور صرف TCP اور UDP handle کیے جاتے ہیں۔ اگر آپ کی آدھی team Linux servers پر اور باقی Docker Desktop پر ہے تو توقع رکھیں کہ ایک ہی file مختلف طرح سے کام کرے گی۔

Host mode اس وقت استعمال کریں جب آپ کو host کے interfaces درکار ہوں۔ Connection problem حل کرنے کے لیے اسے استعمال نہ کریں، کیونکہ عموماً یہ ایک مسئلے کی جگہ اس سے زیادہ مشکل مسئلہ پیدا کر دیتا ہے۔

دو Compose projects کو external network سے مربوط کریں

ایک project کے بنائے ہوئے network کو دوسرا project نہیں دیکھ سکتا۔ اسی لیے proxy/compose.yaml میں موجود reverse proxy، اسی server پر ہونے کے باوجود، app/compose.yaml میں موجود app تک نہیں پہنچ سکتا۔ اس کا حل ایسا network ہے جس کی ملکیت کسی بھی project کے پاس نہ ہو۔

اسے ایک مرتبہ دستی طور پر بنائیں:

docker network create edge

پھر ہر project میں اسے external کے طور پر declare کریں۔ Proxy کا حصہ:

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

Application کا حصہ:

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true Compose کو نیا network بنانے کے بجائے موجودہ network سے attach ہونے کی ہدایت دیتا ہے، اور docker compose down پر اسے برقرار رکھتا ہے۔ الگ name: key کی اہمیت بظاہر کم لگتی ہے، لیکن یہ ضروری ہے: اس کے بغیر Compose بالکل edge نام کے network کو تلاش کرتا ہے، جبکہ اس کے ذریعے آپ اپنی file میں network کا ایک نام اور host پر دوسرا نام استعمال کر سکتے ہیں۔

اگر network موجود نہ ہو تو Compose start ہونے سے انکار کر دیتا ہے اور بتاتا ہے کہ network کو external کے طور پر declare کیا گیا تھا، لیکن وہ نہیں ملا۔ اسے پہلے بنائیں۔

غور کریں کہ application file internal کے ساتھ کیا کرتی ہے۔ Database صرف اسی project-local network پر موجود ہے، اس لیے proxy اس تک نہیں پہنچ سکتا اور صرف app اس تک رسائی حاصل کر سکتا ہے۔ کسی network کے تحت internal: true شامل کرنے سے یہ ایک قدم آگے بڑھتا ہے اور اس کا بیرونی دنیا تک route مکمل طور پر ختم کر دیتا ہے۔ Database کے لیے یہ ایک اچھا default ہے، لیکن اسے set کرنے سے پہلے ایک اہم قیمت سمجھ لیں: internal network پر موجود container کوئی چیز download نہیں کر سکتا۔ اس لیے startup کے وقت apt-get update یا pip install چلانے والا entrypoint hang ہو جائے گا اور پھر timeout کے ساتھ fail ہو جائے گا۔

Routing rules اور certificates کے ساتھ مکمل عملی setup کے لیے ایک Traefik instance کے پیچھے متعدد apps چلانا دیکھیں۔

شائع کردہ ports، UFW کو bypass کرتے ہیں

Compose networking کا یہ وہ حصہ ہے جو security incident میں تبدیل ہو سکتا ہے۔ آپ ایک port publish کرتے ہیں، تصدیق کرتے ہیں کہ UFW فعال ہے اور SSH کے علاوہ ہر چیز کو deny کر رہا ہے، لیکن service پھر بھی internet سے reachable رہتی ہے۔

sudo ufw status
curl http://203.0.113.10:8080

UFW کے مطابق port blocked ہے۔ curl پھر بھی page واپس کرتا ہے۔ کچھ بھی خراب نہیں ہے۔ Docker اپنی address translation اور forwarding rules براہِ راست iptables میں لکھتا ہے۔ Published container port پر آنے والا traffic host تک پہنچنے کے بجائے container کو forward کر دیا جاتا ہے۔ اس لیے وہ اس chain سے نہیں گزرتا جسے UFW مقامی طور پر destined traffic کے لیے manage کرتا ہے۔ Docker کی rules بھی UFW سے پہلے match ہوتی ہیں۔

مختصر حل یہ ہے کہ port صرف وہاں publish کریں جہاں اس کی ضرورت ہو:

    ports:
      - "127.0.0.1:8080:80"

اس سے host side کو loopback سے bind کر دیا جاتا ہے۔ یوں port خود server سے اور SSH tunnel کے ذریعے reachable رہتا ہے، لیکن کسی اور جگہ سے نہیں۔ Public entry point کو reverse proxy کے پیچھے رکھیں، جو جان بوجھ کر 80 اور 443 publish کرے۔ مکمل وضاحت، بشمول ان صورتوں کے لیے DOCKER-USER chain جن میں published port کو filter کرنا ضروری ہو، Docker UFW کو bypass کرتے ہوئے براہِ راست publish کیوں کرتا ہے اور اسے کیسے درست کریں میں موجود ہے۔

چار کمانڈز سے اسے کیسے debug کریں

یہ معلوم کرنے سے شروع کریں کہ ہر container حقیقت میں کس network پر موجود ہے:

docker network inspect shop_default

Containers block ہر منسلک container کو اس کے address کے ساتھ دکھاتا ہے۔ جو service اس فہرست میں موجود نہ ہو، وہ کسی مختلف network پر ہے، host mode میں چل رہی ہے، یا running نہیں ہے۔

اسی network سے منسلک ایک عارضی container کے اندر name resolution کی جانچ کریں۔ اس طرح اپنی images کے اندر کوئی اضافی tooling درکار نہیں ہوتی:

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

nslookup کا fail ہونا name resolution یا network membership کے مسئلے کی نشاندہی کرتا ہے۔ اگر nslookup کامیاب ہو لیکن nc fail ہو، تو service running ہے مگر اس port پر listening نہیں کر رہی، یا اپنے container کے اندر 127.0.0.1 پر listening کر رہی ہے، 0.0.0.0 پر نہیں۔ Development servers میں یہ مسئلہ عام ہے۔ اس کا حل Docker میں نہیں بلکہ application کے bind address میں ہے۔

ایک اور خرابی Docker bug جیسی دکھائی دیتی ہے۔ اگر containers ایک دوسرے سے رابطہ کر سکتے ہوں لیکن office یا VPN network کی کسی machine تک نہیں پہنچ سکتے، تو غالباً Docker subnet اس network کے ساتھ overlap کر رہا ہے۔ Docker default طور پر 172.17.0.0/16 سے آگے کے addresses allocate کرتا ہے۔ Pool کو /etc/docker/daemon.json میں تبدیل کریں:

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

اس کے بعد sudo systemctl restart docker چلائیں اور متاثرہ networks دوبارہ بنائیں، کیونکہ موجودہ network وہی subnet برقرار رکھتا ہے جس کے ساتھ اسے بنایا گیا تھا۔

FAQ

میرے containers ایک دوسرے تک service name کے ذریعے کیوں نہیں پہنچ سکتے؟

وہ ایک ہی network پر نہیں ہیں۔ Compose ہر service کو خودکار طور پر <project>_default پر رکھتا ہے، لیکن جیسے ہی آپ کسی service میں networks: فہرست شامل کرتے ہیں، وہ فہرست اس service کے لیے networks کا مکمل مجموعہ بن جاتی ہے اور default network خودکار طور پر شامل نہیں رہتا۔ docker network inspect <network> چلائیں اور چیک کریں کہ دونوں containers Containers block میں موجود ہیں۔ یہ بھی چیک کریں کہ کسی service میں network_mode: host استعمال نہ ہو، کیونکہ host mode container کسی Docker network پر نہیں ہوتا اور service names resolve نہیں کر سکتا۔

کیا ایک service کو دوسری service تک پہنچنے کے لیے ports publish کرنا ضروری ہے؟

نہیں۔ Compose network پر ہر container کا ہر port اسی network کے دوسرے containers کے لیے قابل رسائی ہوتا ہے۔ ports: صرف container کو Docker کے باہر سے آنے والے network traffic کے لیے expose کرنے کے لیے ہوتا ہے، جبکہ expose: documentation ہے۔ Database port publish کرنا ایک عام اور مہنگی عادت ہے، کیونکہ اس سے database آپ کے server کے public interface پر آ جاتا ہے۔

bridge اور host networking میں کیا فرق ہے؟

Bridge container کو virtual switch پر اپنا network namespace اور address دیتا ہے۔ اس میں containers کے درمیان خودکار name resolution اور outbound traffic translation بھی شامل ہوتی ہے۔ Host container کو براہ راست host کا network stack دیتا ہے۔ اس میں الگ address، service name کے ذریعے resolution، port publishing یا host کے دوسرے listeners سے isolation نہیں ہوتی۔ Bridge default انتخاب ہے اور عموماً یہی درست ہے، الا یہ کہ process کو host کے interfaces درکار ہوں۔

میں دو مختلف Compose files کے containers کو کیسے connect کروں؟

docker network create edge کے ذریعے shared network بنائیں۔ پھر دونوں files میں اسے external: true کے ذریعے declare کریں اور ان services کو اس network سے attach کریں جنہیں ایک دوسرے سے رابطہ کرنا ہے۔ Compose اس network کو نہ create کرے گا اور نہ delete۔ اگر create کرنے کا مرحلہ چھوڑ دیں تو Compose start ہونے سے انکار کر دے گا اور network کو declared external but not found کے طور پر رپورٹ کرے گا۔

UFW port block کرتا ہے، پھر میرا container internet سے کیوں قابل رسائی ہے؟

کیونکہ published port کو Docker کی طرف سے iptables میں شامل کی گئی forwarding rules handle کرتی ہیں۔ یہ rules UFW کی rules سے پہلے match ہوتی ہیں، اور forwarded traffic اس chain سے گزرتا ہی نہیں جسے UFW filter کرتا ہے۔ Host side کو "127.0.0.1:8080:80" کے ذریعے loopback پر bind کریں، اور public services کو ports 80 اور 443 پر reverse proxy کے پیچھے رکھیں۔