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

Ubuntu VPS پر Docker Compose شروع کرنے کا طریقہ

Ubuntu 24.04 پر Docker Engine اور Compose v2 انسٹال کریں، Miniflux اور PostgreSQL کی 2-service stack چلائیں، ufw کے port trap سے بچیں اور volumes کا backup لیں۔

آپ کیا بنائیں گے

Docker Compose اس ویب سائٹ کے تقریباً ہر دوسرے حصے کی بنیاد ہے۔ Nextcloud، Vaultwarden، n8n، Immich، Rocket.Chat، ان تمام رہنماؤں کا آغاز اس ہدایت سے ہوتا ہے: "یہ compose file لکھیں"۔ یہ صفحہ وضاحت کرتا ہے کہ اس file کا اصل مطلب کیا ہے۔ آپ Ubuntu 24.04 پر Docker کے اپنے apt repository سے Docker Engine اور Compose v2 plugin انسٹال کریں گے۔ اس کے بعد دو services پر مشتمل ایک حقیقی stack چلائیں گے: Miniflux، جو ایک چھوٹا RSS reader ہے، اور PostgreSQL۔ یہ جوڑا ان تمام patterns کو استعمال کرتا ہے جو بڑی ایپس میں بھی درکار ہوتے ہیں: pinned images، healthcheck کے ساتھ database، named volume، .env file میں secrets، اور ایسا port جو صرف localhost پر publish ہو۔

انسٹالیشن میں پانچ منٹ لگتے ہیں۔ اس guide کا باقی حصہ ان مسائل کا احاطہ کرتا ہے جو بعد میں دشواری پیدا کرتے ہیں: docker group کا root کا دوسرا نام ہونا، published ports کا آپ کے ufw rules کو براہ راست نظرانداز کرنا، اور docker compose down میں موجود وہ واحد flag جو confirmation prompt کے بغیر آپ کا database حذف کر دیتا ہے۔

ضروریات: ایک نیا Ubuntu 24.04 KVM VPS، sudo استعمال کرنے والا user، اور کم از کم ایک gigabyte RAM۔ اگر Docker پہلے سے انسٹال ہے تو بھی کوئی مسئلہ نہیں؛ پہلے section میں بتایا گیا ہے کہ اسے کیا ہٹانا ہے۔

Ubuntu کے repository سے نہیں، Docker کے repository سے install کریں

پہلا command چلانے سے پہلے دو غلط راستوں کو مسترد کریں۔ Ubuntu کا اپنا docker.io package کام کرتا ہے، لیکن Docker کی releases سے پیچھے رہتا ہے اور plugin layout فراہم نہیں کرتا، جسے باقی تمام components فرض کرتے ہیں۔ دوسرا standalone docker-compose binary ہے، یعنی hyphen والا binary۔ یہ Compose v1 ہے، Python پر مبنی ہے، 2023 سے end-of-life ہے، اور پرانے tutorials کے ناکام ہونے کی وجہ بھی یہی ہے۔ موجودہ Compose، space والا docker compose ہے۔ یہ CLI plugin ہے اور engine کے اسی repository سے install ہوتا ہے۔

اگر ان میں سے کوئی چیز پہلے ہی system پر موجود ہو تو اسے پہلے remove کریں۔ اس میں docker-compose-v2 بھی شامل ہے، جو plugin کی Ubuntu کی اپنی packaging ہے۔ اس طرح تمام components ایک ہی repository سے حاصل ہوں گے:

sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc

نئے VPS پر Package 'docker.io' is not installed, so not removed معمول کا output ہے۔ اس کے بعد Docker کا repository شامل کریں اور install کریں:

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

تینوں layers کی تصدیق کریں:

docker --version
docker compose version
sudo docker run --rm hello-world

پہلے دو commands version strings دکھاتے ہیں۔ Docker Compose version v2.x.x اس بات کی تصدیق کرتا ہے کہ آپ کے پاس plugin موجود ہے، پرانا v1 binary نہیں۔ hello-world کا run Hello from Docker! پر ختم ہونا چاہیے۔ package boot کے وقت service کو enable کرتا ہے؛ systemctl is-enabled docker، enabled دکھاتا ہے۔

Docker گروپ root ہے؛ فیصلہ پوری آگاہی کے ساتھ کریں

اس وقت ہر docker کمانڈ کے لیے sudo درکار ہے، کیونکہ daemon کا socket /var/run/docker.sock، root اور docker گروپ کی ملکیت ہے۔ گروپ کی رکنیت نہ ہونے پر Docker کی سب سے زیادہ تلاش کی جانے والی خرابی ظاہر ہوتی ہے:

permission denied while trying to connect to the Docker daemon socket at
unix:///var/run/docker.sock

معیاری حل:

sudo usermod -aG docker $USER

گروپ کی رکنیت login کے وقت لاگو ہوتی ہے، اس لیے موجودہ shell میں خرابی برقرار رہتی ہے۔ اس session کے لیے newgrp docker چلائیں، یا logout کرکے دوبارہ login کریں؛ اس کے بعد id میں آپ کے گروپس کے درمیان docker درج ہونا چاہیے۔

اب اصل بات واضح طور پر سمجھ لیں: docker گروپ کی رکنیت host پر root کے برابر اختیار دیتی ہے۔ یہ "تقریباً root" یا "اضافی اختیار" نہیں، بلکہ root ہے۔ اس گروپ کا کوئی بھی رکن docker run --rm -it -v /:/host alpine chroot /host چلا کر پورے filesystem کا اختیار حاصل کر سکتا ہے؛ کسی password کی ضرورت نہیں ہوتی۔ یہ گروپ سہولت کے لیے موجود ہے، containment کے لیے نہیں۔

Docker کا rootless mode حقیقی متبادل ہے؛ اس میں daemon خود آپ کے unprivileged user کے طور پر چلتا ہے۔ اس کے کچھ اخراجات ہیں: 1024 سے کم ports کے لیے اضافی setup درکار ہوتی ہے، networking userspace shim کے ذریعے چلتی ہے جس سے قابلِ پیمائش overhead پیدا ہوتا ہے، اور کچھ images حقیقی root کے بغیر درست طور پر کام نہیں کرتیں۔ ایسے single-admin VPS میں جہاں واحد login پہلے ہی sudo رکھتا ہو، یہ گروپ عملی طور پر کچھ نہیں بدلتا۔ اس tutorial میں ہر جگہ یہی مفروضہ ہے، لیکن اسے کبھی بھی sudo سے کم اختیار والا سمجھ کر کسی کو نہ دیں۔

Compose فائل کا جائزہ

ہر stack کے لیے اپنی directory بنائیں۔ directory کا نام project name بن جاتا ہے، جو containers، networks اور volumes کے ناموں کے شروع میں شامل ہوتا ہے:

sudo mkdir -p /opt/miniflux && sudo chown $USER /opt/miniflux && cd /opt/miniflux

compose.yml بنائیں؛ یہ جدید نام ہے، جبکہ docker-compose.yml اب بھی کام کرتا ہے۔ پرانی version: key استعمال نہ کریں۔ یہ obsolete ہے، اور Compose اسے دیکھنے پر warning دیتا ہے۔

services:
  miniflux:
    image: miniflux/miniflux:2.2.9
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - DATABASE_URL=postgres://miniflux:${POSTGRES_PASSWORD}@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=miniflux
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux", "-d", "miniflux"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  db-data:

اوپر کی ہر line ایک فیصلہ ہے۔ انہیں ایک ایک کرکے سمجھیں۔

Image versions کو pin کریں، :latest اور pull کا مطلب unattended upgrade ہے

postgres:16-alpine، postgres:latest نہیں۔ کوئی tag مستقل طور پر frozen نہیں ہوتا: :latest ہر pull کے وقت maintainer کی حالیہ ترین push کردہ version پر دوبارہ resolve ہوتا ہے۔ اسے اس routine upgrade عادت کے ساتھ ملائیں جو آپ ابھی سیکھنے والے ہیں، یعنی docker compose pull && docker compose up -d، تو :latest کا مطلب یہ ہے کہ major-version jumps اس وقت شامل ہو جائیں گے جب upstream انہیں release کرے گا، نہ کہ جب آپ خود منتخب کریں گے۔ PostgreSQL میں یہ محض نظری امکان نہیں: 16 سے 17 تک اچانک jump ہونے پر container incompatible data directory کی وجہ سے crash-loop میں چلا جاتا ہے، کیونکہ Postgres major upgrades کے لیے restart نہیں بلکہ dump اور restore درکار ہوتا ہے۔

کم از کم major version کو pin کریں؛ postgres:16-alpine، 16.x کی patch releases follow کرتا ہے۔ Applications کو miniflux/miniflux:2.2.9 جیسی exact release پر pin کریں۔ Project کی releases page دیکھیں اور file لکھتے وقت جو version current ہو، وہ استعمال کریں۔ اس کے بعد upgrade ایک ایسی one-line edit بن جاتا ہے جو آپ جان بوجھ کر کرتے ہیں اور git diff میں واضح نظر آتی ہے۔

127.0.0.1 پر publish کریں، کیونکہ Docker ufw کے راستے سے بچ نکلتا ہے

"127.0.0.1:8080:8080"، host address، host port، container port۔ زیادہ تر tutorials "8080:8080" لکھتے ہیں، جو 0.0.0.0:8080:8080 کا مختصر طریقہ ہے: یعنی ہر interface پر listening، public interface سمیت۔

یہ وہ trap ہے جس کا سامنا تقریباً ہر شخص کو کم از کم ایک بار ہوتا ہے۔ Docker ایک DNAT rule لکھ کر port publish کرتا ہے۔ یہ rule filtering سے پہلے packet کی destination کو container کے internal IP سے rewrite کرتا ہے، اس لیے packet FORWARD راستہ اختیار کرتا ہے اور INPUT تک کبھی نہیں پہنچتا، جہاں آپ کے ufw rules موجود ہوتے ہیں۔ sudo ufw deny 8080 کامیابی دکھاتا ہے، ufw status port کو denied دکھاتا ہے، اور service پھر بھی پورے internet کو جواب دیتی ہے۔ آپ کا firewall خراب نہیں؛ design کے مطابق اسے bypass کیا جا رہا ہے۔ Docker ufw کو کیوں bypass کرتا ہے، اور container traffic کو حقیقی طور پر filter کرنے کا طریقہ اس mechanism اور ان ports کے لیے DOCKER-USER fix کی وضاحت کرتا ہے جنہیں public رہنا ضروری ہے۔

اس پورے مسئلے کو ختم کرنے والی عادت یہ ہے: published ports کو 127.0.0.1 سے bind کریں، جب تک ایسا نہ کرنے کی کوئی مخصوص وجہ نہ ہو۔ دنیا کے سامنے پیش کی جانے والی ہر چیز کے لیے reverse proxy استعمال کریں۔ یہی کام اس page کے بعد اگلے step کے طور پر Traefik reverse proxy guide میں بنایا گیا ہے: ایک container جو ports 80 اور 443 اپنے پاس رکھتا ہے، hostname کے مطابق باقی تمام services کو TLS کے ساتھ route کرتا ہے۔ اگر آپ پرانے Traefik v2 setup سے آ رہے ہیں تو Traefik v2 سے v3 migration guide renames اور rule changes کی وضاحت کرتی ہے۔

Stack شروع کرنے کے بعد bind کی تصدیق کریں: sudo ss -tlnp | grep 8080 کو 127.0.0.1:8080 دکھانا چاہیے، 0.0.0.0:8080 یا *:8080 نہیں۔

Named volumes اور bind mounts

db-data:/var/lib/postgresql/data ایک named volume ہے: Docker /var/lib/docker/volumes/ کے تحت directory بناتا اور manage کرتا ہے، پھر اسے container میں mount کرتا ہے۔ دوسرا طریقہ bind mount ہے، ./data:/var/lib/postgresql/data، جو host پر آپ کی منتخب کردہ path کو map کرتا ہے۔

عملی طور پر مؤثر تقسیم یہ ہے: صرف containers کے زیر استعمال data کے لیے named volumes، خاص طور پر databases، کیونکہ Docker volume کو image کی متوقع ownership کے ساتھ initialize کرتا ہے اور file permissions درست رہتی ہیں۔ Host سے چھوئی جانے والی files کے لیے bind mounts استعمال کریں، مثلاً وہ config files جنہیں آپ text editor سے edit کرتے ہیں، media library جس میں آپ rsync کرتے ہیں، یا ایسی کوئی چیز جس کی path آپ واضح رکھنا چاہتے ہیں۔ Bind mount کی عام خرابی ownership ہے: container UID 999 کے طور پر چلتا ہے، آپ کی host directory UID 1000 کی ملکیت ہوتی ہے، اور app startup پر اپنے logs میں permission denied کے ساتھ بند ہو جاتی ہے۔ Named volumes اس قسم کے مسئلے کو زیادہ تر ختم کر دیتے ہیں، لیکن data Docker-managed path میں رہتا ہے، جس کا ذکر نیچے ہے۔

environment اور .env، secrets کو git سے باہر رکھیں

${POSTGRES_PASSWORD} آپ کے shell سے read نہیں ہوتا؛ Compose اسے .env نام کی اس file سے interpolate کرتا ہے جو compose.yml کے ساتھ موجود ہوتی ہے۔ اسے بنائیں:

cat > .env <<'EOF'
POSTGRES_PASSWORD=change-me-to-something-long
ADMIN_PASSWORD=change-me-too
EOF
chmod 600 .env
echo ".env" >> .gitignore

حقیقی values openssl rand -hex 24 سے generate کریں۔ جان بوجھ کر base64 کے بجائے hex استعمال کریں: یہ password DATABASE_URL connection string کے اندر جائے گا، اور base64 سے پیدا ہونے والے /، + اور = characters URL parsing توڑ دیتے ہیں۔ خرابی syntax error کے بجائے authentication error کے طور پر ظاہر ہوتی ہے اور پورا ایک evening ضائع کر سکتی ہے۔ .gitignore line پہلے commit سے پہلے شامل کریں: compose file کو publish اور version-control میں رکھا جا سکتا ہے، لیکن .env file کو کبھی نہیں۔ جو secret git history تک پہنچ چکا ہو، اسے rotate کرنا ضروری ہے۔ اگر آپ stack کو کسی missing variable کے ساتھ شروع کرتے ہیں تو Compose واضح warning دیتا ہے اور empty string کے ساتھ جاری رہتا ہے۔ Postgres password کے لیے اس کا نتیجہ broken deployment ہوتا ہے:

WARN[0000] The "POSTGRES_PASSWORD" variable is not set. Defaulting to a blank string.

docker compose config مکمل interpolated file دکھاتا ہے۔ یہ جانچنے کا تیز ترین طریقہ ہے کہ containers کو حقیقت میں کیا ملے گا؛ یاد رکھیں کہ اس output میں آپ کے secrets شامل ہوتے ہیں۔

depends_on کسی چیز کا انتظار نہیں کرتا، جب تک healthcheck شامل نہ کریں

سادہ depends_on: [db] صرف start order کو control کرتا ہے: Compose پہلے Postgres کو launch کرتا ہے اور کچھ دیر بعد app کو، جبکہ Postgres ابھی connections قبول کرنے سے کئی seconds دور ہوتا ہے۔ App database سے connect کرتی ہے، fail ہو جاتی ہے، پھر اس بات پر منحصر ہے کہ اسے کتنی اچھی طرح لکھا گیا ہے، crash یا retry کرتی ہے۔

قابل اعتماد طریقہ وہی ہے جو اوپر والی file استعمال کرتی ہے: db service ایک healthcheck define کرتی ہے؛ Postgres اسی مقصد کے لیے pg_isready فراہم کرتا ہے۔ App، depends_on کو condition: service_healthy کے ساتھ declare کرتی ہے۔ Compose database شروع کرتا ہے، ہر 10 seconds بعد check کرتا ہے، اور check pass ہونے کے بعد ہی Miniflux شروع کرتا ہے۔ اگر database healthy نہ ہو، مثلاً password غلط ہو یا volume corrupt ہو، تو app شروع نہیں ہوتی اور Compose بتاتا ہے کہ کون سی dependency failed ہوئی:

dependency failed to start: container miniflux-db-1 is unhealthy

یہ message آپ کو docker compose logs db کی طرف بھیجتا ہے۔ اصل error وہیں موجود ہوتا ہے۔

restart: unless-stopped

دونوں services پر restart: unless-stopped کا مطلب ہے کہ crash اور VPS reboot کے بعد containers دوبارہ آ جائیں گے، لیکن اگر آپ نے جان بوجھ کر docker compose stop چلایا ہو تو وہ بند رہیں گے۔ متبادل always manual stop کے بعد بھی containers کو دوبارہ شروع کر دیتا ہے، جو عموماً آپ کا مقصد نہیں ہوتا۔ Restart policy کے بغیر kernel-update کے بعد 4 a.m. پر ہونے والا reboot آپ کی services کو خاموشی سے بند کر دیتا ہے، یہاں تک کہ آپ کو اس کا علم ہو۔

روزمرہ کے commands

روزمرہ کے تمام کام پانچ commands سے ہوتے ہیں۔ انہیں project directory سے چلائیں۔

docker compose up -d        # create and start; idempotent, recreates only what changed
docker compose ps           # status, ports, and health of this project's containers
docker compose logs -f miniflux   # follow one service's logs; --tail 100 for recent history
docker compose pull && docker compose up -d   # upgrade to the pinned tags
docker compose down         # stop and remove containers and the network

up -d کو بار بار چلانا محفوظ ہے۔ یہ file کا موجودہ حالت سے تقابل کرتا ہے اور صرف ان services میں تبدیلی کرتا ہے جن کی configuration یا image تبدیل ہوئی ہو۔ upgrade کے لیے commands کی یہ جوڑی وہ images fetch کرتی ہے جن کی طرف آپ کے pinned tags اب اشارہ کر رہے ہیں: postgres:16-alpine کے تحت patch releases، جبکہ exact pin کے لیے کچھ نہیں ہوتا جب تک آپ اسے خود edit نہ کریں۔ یہی اس pin کا مقصد ہے۔ upgrade کے بعد پرانی images جمع ہوتی رہتی ہیں؛ docker image prune -f سے disk space واپس حاصل کریں۔

اب destructive command کے بارے میں واضح تنبیہ: docker compose down محفوظ ہے؛ containers اور network دوبارہ بنائے جا سکتے ہیں، جبکہ آپ کا data volume میں محفوظ ہے۔ docker compose down -v نام زدہ volumes بھی delete کرتا ہے۔ اس سے آپ کا database فوراً ختم ہو جاتا ہے، کوئی confirmation prompt نہیں آتا اور اسے واپس نہیں کیا جا سکتا۔ -v flag تجربات کو ختم کرنے کے لیے ہے؛ real data رکھنے والے stack پر اسے اسی طرح خطرناک سمجھیں جیسے rm -rf کو سمجھتے ہیں۔ /var/lib/docker/volumes/ کے تحت کوئی trash can نہیں ہے۔

چلتے ہوئے container کے اندر ایک بار کے لیے shell کھولنے کے لیے: docker compose exec db psql -U miniflux آپ کو database میں داخل کرتا ہے، جبکہ docker compose exec miniflux sh app میں shell کھولتا ہے۔

آپ کا ڈیٹا دراصل کہاں موجود ہوتا ہے

Named volumes کو project prefix ملتا ہے، اس لیے db-data نامی directory میں موجود miniflux، miniflux_db-data بن جاتا ہے:

docker volume ls
docker volume inspect miniflux_db-data

inspect کے output میں مطلوبہ line شامل ہوتی ہے:

"Mountpoint": "/var/lib/docker/volumes/miniflux_db-data/_data"

یہ directory database ہے، host filesystem پر root کی ملکیت میں ہے، اور down، upgrades اور container rebuilds کے بعد بھی برقرار رہتی ہے۔ آپ کے backups میں بھی عین اسی directory کو شامل کرنا ضروری ہے۔

نامزد volume کا بیک اپ لیں

معیاری طریقہ یہ ہے کہ عارضی container میں volume کو read-only اور host directory کو ساتھ mount کریں، پھر دونوں کے درمیان tar archive بنائیں:

docker run --rm \
  -v miniflux_db-data:/data:ro \
  -v "$PWD":/backup \
  alpine:3.22 tar czf /backup/miniflux-db-$(date +%F).tar.gz -C /data .

کسی installation کی ضرورت نہیں پڑتی اور کوئی process چلتا ہوا باقی نہیں رہتا۔ بحالی اس کا الٹا طریقہ ہے: tar xzf کو نئے خالی volume میں چلائیں اور mounts کی سمت الٹ دیں۔

Database کے لیے ایک اہم احتیاط ہے: چلتے ہوئے Postgres data directory کو tar کرنے سے write کے دوران کی ایسی حالت محفوظ ہو سکتی ہے جس میں database درست طور پر start نہ ہو۔ یا تو tar مکمل ہونے کے چند seconds کے لیے docker compose stop، یا بہتر یہ ہے کہ logical dump لیں، کیونکہ وہ ساخت کے اعتبار سے consistent ہوتا ہے:

docker compose exec -T db pg_dump -U miniflux miniflux | gzip > miniflux-$(date +%F).sql.gz

-T اس pseudo-terminal کو disable کرتا ہے جسے Compose بطور default allocate کرتا ہے۔ Dump output کو TTY کے ذریعے pipe کرنے سے وہ خراب ہو سکتا ہے۔ ان میں سے کسی ایک کو cron میں شامل کریں اور نتیجہ VPS سے باہر copy کریں؛ data والی اسی disk پر موجود backup، backup نہیں بلکہ صرف ایک copy ہے۔ Nextcloud گائیڈ انہی دو طریقوں کے گرد مکمل scheduled routine بناتی ہے۔

ناکامی کی صورتیں اور دکھائی دینے والے پیغامات

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock، آپ ابھی docker گروپ میں شامل نہیں ہیں، یا شامل تو ہیں لیکن موجودہ session اس تبدیلی سے پہلے شروع ہوا تھا۔ id آپ کے مؤثر گروپس دکھاتا ہے؛ newgrp docker موجودہ shell کو درست کرتا ہے، جبکہ logout کرکے دوبارہ login کرنے سے تمام sessions درست ہو جاتے ہیں۔

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?، مسئلہ مختلف ہے: daemon خود بند ہے۔ sudo systemctl status docker اور sudo journalctl -u docker -n 50 وجہ بتاتے ہیں۔ VPS پر عام وجہ disk کا بھر جانا ہے؛ پہلے df -h /var/lib/docker چلائیں۔

Bind for 127.0.0.1:8080 failed: port is already allocated، کسی دوسرے container نے وہ host port پہلے ہی publish کر رکھا ہے۔ docker ps بتاتا ہے کہ کون سا container ہے؛ عموماً کئی ہفتے پہلے کے تجرباتی docker run سے بچا ہوا container اس کی وجہ ہوتا ہے۔ اگر docker ps کا output خالی ہو تو کوئی non-Docker process port استعمال کر رہا ہے: sudo ss -tlnp | grep 8080 اس process کا نام بتاتا ہے۔

yaml: line 14: did not find expected key، نام زدہ line پر یا اس سے عین اوپر indentation کی خرابی ہے۔ Compose files YAML ہوتی ہیں: دو spaces کی indentation استعمال کریں، صرف spaces لکھیں، اور کہیں بھی tab character موجود ہو تو file ناقابلِ استعمال ہو جاتی ہے۔ docker compose config file شروع کیے بغیر اس کی validation کرتا ہے، اس لیے ہر edit کے بعد اسے چلانا ایک آسان اور مفید عادت ہے۔

ufw کا حیران کن مسئلہ کوئی error ظاہر نہیں کرتا، اور یہی اسے خطرناک بناتا ہے: deploy کامیاب ہو جاتا ہے، ufw status درست دکھائی دیتا ہے، لیکن باہر سے کیا گیا port scan پھر بھی آپ کا database تلاش کر لیتا ہے۔ اوپر ports والے حصے کو دوبارہ پڑھیں، ہر ports: entry میں missing 127.0.0.1: prefix تلاش کریں، اور مختلف machine سے curl http://your-vps-ip:8080 کے ذریعے تصدیق کریں؛ مطلوبہ جواب connection refused ہے۔

یہاں سے Traefik guide اس single stack کو ایک HTTPS entry point کے پیچھے متعدد ایپس میں تبدیل کرتی ہے، جبکہ 2026 میں self-host کرنے کے قابل چیزیں وہ فہرست ہے جسے آپ اس کے ذریعے چلانے کے لیے استعمال کر سکتے ہیں۔ جب ان میں سے کئی stacks چلنے لگیں اور ہر stack اپنا login form بنا لے، تو Authentik جیسا self-hosted SSO server انہیں اسی proxy کے پیچھے ایک account میں یکجا کر دیتا ہے۔

VPS پر Minecraft server جیسا game server مشق کے لیے ایک دوستانہ ابتدائی Compose project ہے۔ اگر آپ کسی ایسی چیز پر سیکھنا چاہیں جسے روزانہ کھولتے ہیں، تو openGym، ایک self-hosted workout tracker ایک چھوٹا stack ہے جو image tag کے بجائے git tag پر pinned ہے، اور پہلے passkey کا اندراج کرنے سے پہلے اس کے سامنے TLS درکار ہے۔ Photos عموماً وہ پہلی چیز ہوتی ہیں جسے لوگ کسی دوسرے کے cloud سے واپس لانا چاہتے ہیں، اور PhotoPrism اور Immich کا موازنہ یہ طے کرنے میں مدد دیتا ہے کہ کسی ایک کے لیے volume مختص کرنے سے پہلے کم از کم کتنی RAM اور backup routine درکار ہوگی۔ جب دو services ناکافی محسوس ہونے لگیں، تو AFFiNE کو Notion-style workspace کے طور پر کھڑا کرنا چار containers میں انہی patterns کو استعمال کرتا ہے، اور یہ جانچنے کا مناسب طریقہ ہے کہ اوپر بیان کیے گئے pinned tags، healthchecks اور named volumes اب معمول بن چکے ہیں یا نہیں۔

FAQ

مجھے "permission denied while trying to connect to the Docker daemon socket" کیوں ملتا ہے؟

آپ کا صارف docker گروپ میں شامل نہیں ہے، یا اسے موجودہ session شروع ہونے کے بعد شامل کیا گیا تھا۔ گروپ کی رکنیت صرف login کے وقت لاگو ہوتی ہے۔ sudo usermod -aG docker $USER چلائیں، پھر newgrp docker چلائیں یا logout کرکے دوبارہ login کریں، اور id سے تصدیق کریں۔ یہ گروپ host تک root کے مساوی رسائی دیتا ہے، اس لیے صرف ان صارفین کو شامل کریں جنہیں آپ sudo کی اجازت دیتے۔

کیا docker compose down میرا data حذف کر دیتا ہے؟

سادہ docker compose down ایسا نہیں کرتا۔ یہ containers اور project network ہٹا دیتا ہے، جبکہ named volumes برقرار رہتے ہیں اور اگلا up -d انہیں دوبارہ attach کر دیتا ہے۔ docker compose down -v تباہ کن طریقہ ہے: یہ named volumes حذف کر دیتا ہے، یعنی آپ کا database، اور نہ کوئی confirmation دیتا ہے نہ undo کا اختیار۔ حقیقی data والے stack پر -v کبھی نہ چلائیں، جب تک آپ کے پاس تصدیق شدہ backup موجود نہ ہو۔

docker-compose اور docker compose میں کیا فرق ہے؟

docker-compose (hyphen) Compose v1 ہے۔ یہ ایک standalone Python binary ہے جو 2023 میں end of life تک پہنچ گئی، اس لیے اسے نئے servers پر install نہیں کرنا چاہیے۔ docker compose (space) Compose v2 ہے۔ یہ Docker CLI کے لیے Go plugin ہے، اور Docker کی apt repository سے docker-compose-plugin کے طور پر install ہوتا ہے۔ Commands اور YAML تقریباً مکمل طور پر compatible ہیں، اس لیے جب کوئی پرانا tutorial docker-compose up کہے تو docker compose up لکھیں۔

ufw port کو block کرنے کے باوجود میں اپنے Docker container تک internet سے کیوں پہنچ سکتا ہوں؟

اس کی وجہ یہ ہے کہ Docker ports کو iptables کی PREROUTING chain میں DNAT rules کے ذریعے publish کرتا ہے۔ تبدیل شدہ packets Docker کی اپنی chains کے ذریعے FORWARD path اختیار کرتے ہیں، اس لیے وہ INPUT chain تک نہیں پہنچتے جہاں ufw کے rules لاگو ہوتے ہیں۔ لہٰذا ufw deny 8080 published container port پر کوئی اثر نہیں ڈالتا۔ مسئلہ اصل مقام پر حل کریں: 127.0.0.1: پر publish کریں اور services کو reverse proxy کے ذریعے expose کریں۔

کیا مجھے named volume استعمال کرنا چاہیے یا bind mount؟

صرف container کے زیر استعمال data کے لیے named volumes استعمال کریں، خاص طور پر databases کے لیے، کیونکہ Docker وہ ownership مقرر کرتا ہے جس کی image کو توقع ہوتی ہے اور permissions درست طور پر کام کرتی ہیں۔ ان files کے لیے bind mounts استعمال کریں جنہیں آپ host سے بھی manage کرتے ہیں: وہ configs جنہیں آپ edit کرتے ہیں، وہ media جسے آپ upload کرتے ہیں، اور ہر وہ چیز جس کا path آپ واضح رکھنا چاہتے ہیں۔ اگر bind mount پر permission denied کے ساتھ container startup میں fail ہو جائے تو host اور container کے UID میں mismatch سب سے پہلے check کریں۔