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

Docker Compose میں .env، env_file اور environment کا فرق

Docker Compose میں .env، env_file اور environment ایک جیسے نہیں۔ جانیں placeholders، container variables اور secrets کے درست استعمال، نیز precedence میں کون سی value جیتتی ہے۔

env فائل کہلانے والی تین چیزیں

Docker Compose میں تین الگ mechanisms ہیں جن کے نام ایک دوسرے سے الجھن پیدا کرنے کی حد تک ملتے جلتے ہیں۔ .env فائل خود compose.yaml کے اندر موجود ${VARIABLE} placeholders کی قدر متعین کرتی ہے۔ یہ عمل Compose کے YAML پڑھنے کے بعد اور کسی بھی validation یا execution سے پہلے ہوتا ہے۔ env_file: attribute key/value pairs والی فائل کو container کے environment میں load کرتا ہے۔ environment: attribute variables کو براہِ راست container پر set کرتا ہے، اور یہ variables compose فائل میں لکھی جاتی ہیں۔ یہ ایک دوسرے کا متبادل نہیں ہیں۔ جب ان میں سے دو ایک ہی key set کریں تو نتیجہ documented precedence order کے مطابق طے ہوتا ہے۔

یہ guide ہر mechanism کو عملی طور پر دکھاتی ہے۔ پھر ایک قابلِ اجرا command کے ذریعے precedence ثابت کرتی ہے۔ اس کے بعد زیادہ اہم نکتے پر بات کرتی ہے: environment variables ہر وہ شخص پڑھ سکتا ہے جو docker inspect چلا سکتا ہو، اس لیے passwords ان میں نہیں رکھنے چاہییں۔ اگر آپ compose فائلوں کے عمومی استعمال سے نئے ہیں تو پہلے VPS پر Docker Compose کی بنیادی باتیں پڑھیں، پھر configuration کے لیے یہاں واپس آئیں۔

.env فائل compose file کے لیے ہوتی ہے، container کے لیے نہیں

ایک directory بنائیں اور اس میں دو files رکھیں۔

mkdir -p ~/envdemo && cd ~/envdemo
printf 'ALPINE_TAG=3.20\n' > .env
services:
  demo:
    image: alpine:${ALPINE_TAG}
    command: printenv ALPINE_TAG

اب Compose سے پوچھیں کہ اس نے اصل میں کیا parse کیا ہے۔

docker compose config

Output میں image: alpine:3.20 دکھائی دیتا ہے۔ Placeholder ختم ہو چکا ہے، کیونکہ Compose نے file load کرتے وقت interpolation کر دی تھی۔ Compose project directory میں .env تلاش کرتا ہے: اگر آپ --project-directory set کریں تو اس کے ذریعے دی گئی directory، ورنہ -f کے ساتھ دی گئی پہلی file کی directory، اور بصورت دیگر موجودہ directory۔ یہ YAML values میں موجود ${NAME} placeholders کو substitute کرتا ہے۔ Keys میں کبھی interpolation نہیں ہوتی، اور دوہر ا $$ substitution کے بجائے literal dollar sign پیدا کرتا ہے۔

اب service چلائیں۔

docker compose run --rm demo

printenv ALPINE_TAG status 1 کے ساتھ exit کرتا ہے اور کچھ print نہیں کرتا۔ یہ variable container کے اندر موجود نہیں ہے۔ یہی سب سے عام غلط فہمی ہے: .env نے compose file کو configure کیا تھا، process کو نہیں۔ POSTGRES_PASSWORD=hunter2 پر مشتمل .env file آپ کے database کے لیے بالکل کچھ نہیں کرتی، جب تک compose file کا کوئی حصہ اس کا حوالہ نہ دے۔

${NAME:-default} اس وقت fallback value فراہم کرتا ہے جب variable unset یا empty ہو۔ ${NAME:?message} Compose کو start ہونے سے روک کر آپ کا message print کرتا ہے۔ ایسی value کے لیے یہی درست انتخاب ہے جس کا کوئی محفوظ default موجود نہ ہو۔

env_file کنٹینر میں variables لوڈ کرتا ہے

`env_file:` attribute ایک یا زیادہ files کے نام بیان کرتا ہے۔ ان files کا content کنٹینر کے environment variables بن جاتا ہے۔

printf 'GREETING=from_env_file\nAPP_MODE=production\n' > app.env
services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
docker compose run --rm demo

یہ `from_env_file print کرتا ہے۔ File format سادہ KEY=value lines پر مشتمل ہوتا ہے، ہر line الگ ہوتی ہے، اور # سے comment شروع ہوتا ہے۔ یہ shell نہیں ہے، تاہم Compose اسے shell جیسے چند rules کے ساتھ parse کرتا ہے۔ اطراف کے quotation marks ہٹا دیے جاتے ہیں، اس لیے KEY="value" اور KEY=value کا نتیجہ ایک جیسا ہوتا ہے۔ Double-quoted اور unquoted values میں ${...} placeholders interpolate ہوتے ہیں، جبکہ single-quoted values کو جوں کا توں استعمال کیا جاتا ہے۔ export prefix قابل قبول ہے، لیکن ضروری نہیں۔ = sign کے اطراف موجود spaces trim کر دیے جاتے ہیں۔ خاص احتیاط inline comment کے بارے میں کریں: unquoted value میں space کے بعد # آئے تو comment شروع ہو جاتا ہے، اس لیے ایسی ہر value کو quote کریں جس میں #` موجود ہو۔

اگر `env_file` path موجود نہ ہو تو یہ error ہے اور Compose رک جاتا ہے۔ اگر file کا غیر موجود ہونا جائز ہو تو اسے optional mark کریں:

    env_file:
      - path: ./app.env
        required: false

environment متغیرز inline طور پر set کرتا ہے

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    environment:
      GREETING: from_environment

دو syntax قبول کیے جاتے ہیں: اوپر دکھایا گیا mapping form اور - GREETING=from_environment استعمال کرنے والا list form۔ دونوں کا رویہ یکساں ہے۔ دونوں میں ایک اضافی طریقہ بھی موجود ہے: جس key کی کوئی value نہ ہو، وہ اس variable کو اس shell سے pass through کرتی ہے جہاں آپ نے docker compose چلایا تھا۔ list form میں یہ ایک الگ - GREETING ہوتا ہے، جبکہ mapping form میں یہ GREETING: ہوتا ہے اور colon کے بعد کچھ نہیں لکھا جاتا۔

    environment:
      - GREETING
GREETING=from_my_shell docker compose run --rm demo

یہ from_my_shell print کرتا ہے۔ shell میں GREETING set کیے بغیر اسے چلائیں تو Compose کچھ set نہیں کرتا اور کوئی warning بھی نہیں دیتا۔ خاموش pass-through failure کے بارے میں جاننا ضروری ہے، کیونکہ empty password variable کے ساتھ شروع ہونے والی service اکثر کامیابی سے start ہو جاتی ہے اور صرف مکمل طور پر غیر محفوظ رہ جاتی ہے۔

کون سی قدر غالب ہوتی ہے

Docker ترجیح کی ترتیب دستاویز کرتا ہے، جس میں سب سے زیادہ ترجیح پہلے آتی ہے: کمانڈ لائن پر docker compose run -e، پھر environment یا env_file، جن کی قدر آپ کے shell یا env file سے interpolate ہوتی ہے، پھر compose file میں سادہ environment، اس کے بعد env_file، اور آخر میں image میں شامل ENV directive۔

روزمرہ کام کے لیے مختصر اصول یہ ہے: environment:، env_file: پر غالب ہوتی ہے، جبکہ کمانڈ لائن پر -e دونوں پر غالب ہوتی ہے۔ اسے ایک ہی file میں ثابت کریں۔

services:
  demo:
    image: alpine:3.20
    command: printenv GREETING
    env_file:
      - ./app.env
    environment:
      GREETING: from_environment
docker compose run --rm demo
docker compose run --rm -e GREETING=from_cli demo printenv GREETING

پہلی command from_environment دکھاتی ہے، اس لیے environment: نے app.env میں موجود قدر کو override کر دیا۔ دوسری command from_cli دکھاتی ہے۔ compose file میں کوئی چیز کمانڈ لائن کی قدر کو override نہیں کرتی۔

اگر container اس طرح کام کر رہا ہو جیسے آپ کی configuration لاگو ہی نہیں ہوئی، تو اندازہ نہ لگائیں۔ docker compose config مکمل طور پر resolved file دکھاتی ہے، جبکہ docker compose config --environment وہ interpolation variables دکھاتی ہے جن سے Compose کام کر رہا ہے۔ زیادہ تر "میری env file نظرانداز ہو رہی ہے" والی رپورٹس میں اصل مسئلہ یہ ہوتا ہے کہ قدر دو مختلف سطحوں پر دو مرتبہ set کی گئی ہوتی ہے۔

ماحولیاتی متغیرات کیوں افشا ہو جاتی ہیں

environment: میں password مقرر کریں، تو یہ container کی configuration میں disk پر محفوظ ہو جاتا ہے اور docker group کے ہر user کو نظر آ سکتا ہے۔

docker compose run -d --name leaky -e DB_PASSWORD=hunter2 demo sleep 300
docker inspect leaky --format '{{json .Config.Env}}'

Output میں "DB_PASSWORD=hunter2" plain text کی صورت میں شامل ہوتا ہے۔ مزید تین paths اسی value کو ظاہر کرتے ہیں۔ docker compose config اسے terminal پر print کرتا ہے، جس کے نتیجے میں یہ support forum میں paste ہو سکتا ہے۔ Child processes کو یہ variable default طور پر وراثت میں ملتا ہے، جب تک parent انہیں replacement environment کے ساتھ شروع نہ کرے۔ اسی user کے طور پر چلنے والا process جس کے طور پر PID 1 چل رہا ہو، یا جس کے پاس CAP_SYS_PTRACE ہو، /proc/1/environ سے اسے پڑھ سکتا ہے۔ ایسے container میں جہاں ہر چیز root کے طور پر چلتی ہو، یہ ہر process پر لاگو ہوتا ہے۔ اگر application unprivileged user کے طور پر چل رہی ہو جبکہ PID 1 root کے طور پر چل رہا ہو، تو اسے اس file پر permission error ملے گا؛ تاہم variable اس کے اپنے environment میں پھر بھی موجود رہے گا۔ مزید یہ کہ application کے crash handlers عموماً پورے environment کو log یا error report میں dump کر دیتے ہیں۔

docker group کی رکنیت host پر عملاً root کے برابر اختیار دیتی ہے، اس لیے اسے ایسی privilege boundary نہیں سمجھنا چاہیے جس پر انحصار کیا جا سکے۔ VPS پر کم سے کم مراعات والے user accounts کی guide وضاحت کرتی ہے کہ کسی بھی shared server پر اس group کی رکنیت محدود رکھنا کیوں ضروری ہے۔

Compose secrets قدر کو فائل میں رکھتے ہیں

Compose فائل پر مبنی secrets کو support کرتا ہے۔ قدر کو environment میں شامل کرنے کے بجائے container کے اندر ایک فائل کے طور پر mount کیا جاتا ہے۔

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
secrets:
  db_password:
    file: ./db_password.txt

secret کو container کے اندر /run/secrets/db_password پر mount کیا جاتا ہے۔ slash کے بعد موجود نام top-level secrets: block سے لیا گیا secret name ہے۔

_FILE suffix Docker Official Images میں استعمال ہونے والا ایک convention ہے، جس میں postgres، mysql اور mariadb شامل ہیں۔ ان images کے entrypoint scripts VARNAME_FILE کو check کرتے ہیں، فائل پڑھتے ہیں، اور اس کے contents استعمال کرتے ہیں۔ یہ Docker feature نہیں ہے، اس لیے صرف وہاں کام کرتا ہے جہاں image اسے implement کرتی ہو۔ یہ فرض کرنے سے پہلے کہ SOMETHING_FILE کو honour کیا جائے گا، image documentation دیکھیں۔ جو applications اسے support نہیں کرتیں، وہ اکثر startup کے وقت خود فائل پڑھ سکتی ہیں۔ متبادل طور پر path pass کریں اور اپنے entrypoint کو یہ کام کرنے دیں۔

چلتے ہوئے container کے اندر سے تصدیق کریں:

docker compose exec db cat /run/secrets/db_password
docker compose exec db printenv POSTGRES_PASSWORD

پہلی command password print کرتی ہے۔ دوسری command کچھ print نہیں کرتی، کیونکہ قدر environment میں شامل ہی نہیں ہوئی۔ یہی اس کا مقصد ہے: اس container پر docker inspect صرف بے ضرر path دکھاتا ہے۔

Host پر source file کو محفوظ رکھیں، کیونکہ secret کی رازداری اس کے پیچھے موجود file جتنی ہی ہوتی ہے:

chmod 600 db_password.txt

VPS پر عملی درمیانی راستہ

بہت سی self-hosted images _FILE variables کو support نہیں کرتیں، اس لیے داخل ہونے کا واحد طریقہ environment variables ہیں۔ ایک ہی administrator VPS پر حقیقت پسندانہ مقصد یہ ہے کہ values آپ کے project directory میں موجود ایسی file میں نہ رہیں جسے تمام users پڑھ سکتے ہوں، اور انہیں git سے بھی باہر رکھا جائے۔

sudo install -o root -g root -m 600 /dev/null /etc/myapp/app.env
sudo nano /etc/myapp/app.env
    env_file:
      - /etc/myapp/app.env

install -m 600 file بناتے وقت ہی اس کا mode مقرر کر دیتا ہے، اس لیے کوئی ایسا وقفہ نہیں آتا جس میں اسے ہر user پڑھ سکے۔ اس file کا مالک root ہوتا ہے، لہٰذا machine پر موجود non-root user اسے نہیں پڑھ سکتا؛ تاہم جو بھی docker چلا سکتا ہو، وہ container سے value پھر بھی پڑھ سکتا ہے۔ *.env اور .env کو .gitignore میں شامل کریں، اور اس کے بجائے ایک app.env.example commit کریں جس میں key names ہوں اور values خالی ہوں۔ commit کیا گیا password تبدیل کرنا ضروری ہوتا ہے۔

کسی value کو rotate کرنے کا مطلب service کو restart کرنا ہے۔ Environment variables container process شروع ہوتے وقت صرف ایک بار پڑھے جاتے ہیں، اس لیے file میں ترمیم کرنے سے کچھ تبدیل نہیں ہوتا جب تک آپ docker compose up -d --force-recreate db نہ چلائیں۔ یہی طریقہ VPS پر HTTPS کے پیچھے n8n گائیڈ میں استعمال کیا گیا ہے، جہاں encryption key compose file سے باہر رکھی جاتی ہے۔

ماحول کے لحاظ سے configuration الگ کرنا

Compose پہلے سے project directory سے .env پڑھتا ہے۔ اسے کسی دوسری جگہ سے پڑھانے کے لیے --env-file استعمال کریں۔

docker compose --env-file .env.staging config

متعدد files ترتیب سے پڑھی جاتی ہیں، اور بعد والی files پہلے والی settings کو override کرتی ہیں۔ secret کے بغیر defaults کو ایک committed file میں رکھیں، جبکہ secrets ایسی file میں رکھیں جو کبھی server سے باہر نہ جائے۔ یہی اصول env_file: پر بھی لاگو ہوتا ہے؛ duplicate key کی صورت میں فہرست میں آخری file مؤثر ہوتی ہے۔

FAQ

میری .env فائل container کے اندر نظرانداز کیوں ہو رہی ہے؟

اسے نظرانداز نہیں کیا جا رہا۔ .env فائل compose file میں موجود ${NAME} placeholders کی جگہ values شامل کرتی ہے، اور Compose کی اپنی variables، مثلاً COMPOSE_PROJECT_NAME یا COMPOSE_FILE، بھی set کر سکتی ہے۔ یہ container کے اندر variables کبھی set نہیں کرتی۔ value کو container تک پہنچانے کے لیے اس کا حوالہ دیں: environment: { KEY: "${NAME}" }، یا اس کے بجائے env_file: ./that-file.env استعمال کریں۔

کیا environment، env_file کو override کرتا ہے، یا اس کے برعکس؟

environment: کو ترجیح حاصل ہے۔ Docker کی دستاویزی ترجیحی ترتیب میں environment attribute، env_file attribute سے اوپر ہے، جبکہ دونوں command line پر docker compose run -e سے نیچے ہیں۔ اگر کوئی key دونوں جگہ set ہو تو env_file میں موجود value خاموشی سے استعمال نہیں ہوتی۔

Compose کی استعمال کرنے والی آخری value کیسے دیکھوں؟

docker compose config چلائیں تاکہ تمام interpolation لاگو ہونے کے بعد مکمل resolved compose file ظاہر ہو۔ پہلے سے running container کے لیے docker inspect <container> --format '{{json .Config.Env}}' بالکل وہی value دکھاتا ہے جو اس کے process کو موصول ہوئی۔

کیا Compose secrets encrypted ہوتے ہیں؟

نہیں۔ File-based secret، /run/secrets/<name> پر container کے اندر plain file کے طور پر mount ہوتا ہے، جبکہ source file host disk پر unencrypted رہتی ہے۔ فائدہ encryption نہیں بلکہ scope ہے: value container environment سے باہر، docker inspect output سے باہر، اور ان crash dumps سے باہر رہتی ہے جو environment print کرتے ہیں۔

کیا میں env file میں quotes اور spaces استعمال کر سکتا ہوں؟

ہاں۔ Compose بیرونی quotes ہٹا دیتا ہے، اس لیے KEY="value with spaces" اور KEY=value with spaces دونوں value with spaces فراہم کرتے ہیں۔ جب value میں ایسا $ ہو جس کی interpolation نہیں ہونی چاہیے تو single quotes استعمال کریں، اور ایسی ہر value کو quote کریں جس میں # ہو، کیونکہ unquoted صورت میں یہ comment شروع کرتا ہے۔ = کے اردگرد موجود spaces trim کر دیے جاتے ہیں، اس لیے KEY = value پھر بھی KEY set کرتا ہے۔

کیا یہ مضمون مفید تھا؟