SSD Nodes Learn 8GB RAM — $66/साल
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-01

Docker Compose में .env, env_file और environment का अंतर

Docker Compose में .env, env_file और environment के अंतर, precedence order और secrets रखने की सही जगह समझें। कौन-सा विकल्प जीतता है, command से जांचें।

env file कहे जाने वाले तीन अलग-अलग साधन

Docker Compose में लगभग समान नाम वाले तीन अलग-अलग तंत्र होते हैं। .env फ़ाइल, compose.yaml के अंदर मौजूद ${VARIABLE} placeholders को भरती है, और यह Compose द्वारा फ़ाइल को parse करने से पहले होता है। env_file: attribute, key/value pairs वाली फ़ाइल को container के environment में लोड करता है। environment: attribute, compose फ़ाइल में लिखे गए variables को सीधे container पर सेट करता है। ये एक-दूसरे के विकल्प नहीं हैं। जब इनमें से दो एक ही key सेट करते हैं, तो विजेता documented precedence order से तय होता है।

यह guide प्रत्येक तंत्र को कार्य करते हुए दिखाती है। यह एक ऐसे command से precedence को साबित करती है जिसे आप चला सकते हैं। इसके बाद यह अधिक महत्वपूर्ण विषय समझाती है: docker inspect चलाने वाला कोई भी व्यक्ति environment variables को पढ़ सकता है। इसलिए passwords को इनमें नहीं रखना चाहिए। यदि आप compose फ़ाइलों से नए हैं, तो VPS पर Docker Compose की मूल बातें से शुरू करें और configuration के लिए यहां वापस आएं।

.env फ़ाइल compose फ़ाइल के लिए है, container के लिए नहीं

एक directory बनाएँ और उसमें दो फ़ाइलें रखें।

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

आउटपुट में image: alpine:3.20 दिखता है। Placeholder हट गया है, क्योंकि interpolation parse के समय हुआ। Compose project directory में .env खोजता है। यह वही directory है जिसमें compose फ़ाइल होती है। फिर उसे मिलने वाले हर ${NAME} को बदल देता है।

अब service चलाएँ।

docker compose run --rm demo

printenv ALPINE_TAG status 1 के साथ exit करता है और कुछ भी print नहीं करता। यह variable container के अंदर मौजूद नहीं है। यही सबसे आम गलतफ़हमी है: .env ने compose फ़ाइल को configure किया था, process को नहीं। .env फ़ाइल में POSTGRES_PASSWORD=hunter2 होने से आपके database पर कोई प्रभाव नहीं पड़ता, जब तक compose फ़ाइल का कोई भाग उसका reference न दे।

${NAME:-default} variable के unset या empty होने पर fallback देता है। ${NAME:?message} Compose को start होने से रोकता है और आपका message print करता है। ऐसे value के लिए यह सही विकल्प है जिसका कोई सुरक्षित default नहीं है।

env_file कंटेनर में variables लोड करता है

env_file: attribute एक या अधिक files के नाम निर्दिष्ट करता है। इन files की contents container 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 plain KEY=value lines का होता है, प्रत्येक line में एक variable होता है। # से comment शुरू होता है। यह shell format नहीं है। अधिकांश मामलों में quotes value का हिस्सा बने रहते हैं, और export prefixes की आवश्यकता नहीं होती। = sign के आसपास spaces न रखें, क्योंकि KEY = value ऐसा variable बनाता है जिसका नाम literalmente KEY होता है और जिसकी value की शुरुआत में एक leading space होती है।

यदि env_file path मौजूद नहीं है, तो यह error है और Compose रुक जाता है। यदि file का अनुपस्थित होना वैध स्थिति हो सकती है, तो उसे optional mark करें:

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

environment inline variables सेट करता है

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

दो syntax स्वीकार किए जाते हैं: ऊपर दिया गया mapping form और - GREETING=from_environment का उपयोग करने वाला list form। दोनों का व्यवहार एक जैसा है। List form में एक अतिरिक्त सुविधा है: बिना value वाली bare key उस shell से variable को pass through करती है, जिसमें आपने docker compose चलाया था।

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

यह from_my_shell प्रिंट करता है। Shell में GREETING सेट किए बिना इसे चलाने पर Compose कुछ भी सेट नहीं करता और कोई warning भी नहीं दिखाता। ऐसे silent pass-through failures की जानकारी रखना आवश्यक है, क्योंकि empty password variable के साथ शुरू होने वाली service अक्सर सफलतापूर्वक शुरू हो जाती है और उसका access पूरी तरह खुला रह जाता है।

कौन-सा प्रभावी होता है

Docker प्राथमिकता क्रम को उच्चतम से निम्नतम तक दस्तावेज़ित करता है: कमांड लाइन पर docker compose run -e, फिर environment या env_file, जिनका मान आपके shell या env file से इंटरपोलेट होता है, फिर 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

पहला from_environment प्रिंट करता है, इसलिए environment: ने app.env में मौजूद मान को अधिलेखित कर दिया। दूसरा from_cli प्रिंट करता है। compose file में कोई भी चीज़ कमांड लाइन के मान को अधिलेखित नहीं करती।

जब कोई container ऐसा व्यवहार करे जैसे आपका configuration लागू ही नहीं हुआ, तो अनुमान न लगाएँ। docker compose config पूरी तरह resolved file प्रिंट करता है, और docker compose config --environment वे interpolation variables प्रिंट करता है जिनसे Compose काम कर रहा है। “मेरी env file को अनदेखा किया जा रहा है” वाली अधिकांश समस्याओं में एक ही मान दो अलग स्तरों पर सेट होता है।

पर्यावरण चर क्यों लीक होते हैं

environment: में पासवर्ड सेट करने पर वह डिस्क पर container के configuration में संग्रहीत हो जाता है। 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 भी यही मान उजागर करते हैं। docker compose config इसे terminal पर प्रदर्शित करता है। इसी कारण यह किसी support forum में paste हो जाता है। container के अंदर चलने वाली कोई भी process /proc/1/environ पढ़ सकती है। प्रत्येक child process को यह variable विरासत में मिलता है। Application crash handlers अक्सर पूरे environment को log या error report में dump कर देते हैं।

docker group की membership host पर प्रभावी रूप से root access देती है। इसलिए इसे privilege boundary मानकर निर्भर नहीं किया जा सकता। VPS पर least privilege user accounts की guide बताती है कि किसी भी shared box पर इस group की membership सीमित रखना क्यों आवश्यक है।

Compose secrets में मान को फ़ाइल में रखें

Compose फ़ाइल-आधारित secrets का समर्थन करता है। मान को 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 भी शामिल हैं। ये entrypoint scripts VARNAME_FILE की जाँच करती हैं, फ़ाइल पढ़ती हैं और उसकी सामग्री का उपयोग करती हैं। यह Docker की सुविधा नहीं है। इसलिए यह केवल उन्हीं images में काम करता है जो इसे लागू करती हैं। यह मानने से पहले कि SOMETHING_FILE को स्वीकार किया जाएगा, image का documentation जाँचें। जो applications इसका समर्थन नहीं करतीं, वे अक्सर startup के समय फ़ाइल को स्वयं पढ़ सकती हैं। दूसरा विकल्प है कि path पास करें और अपना entrypoint यह कार्य करे।

चल रहे container के अंदर से सत्यापित करें:

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

पहला command password प्रदर्शित करता है। दूसरा कुछ भी प्रदर्शित नहीं करता, क्योंकि मान environment में कभी प्रवेश नहीं करता। यही इसका उद्देश्य है: इस container पर docker inspect केवल सुरक्षित path दिखाता है।

Host पर source file को सुरक्षित रखें, क्योंकि secret उतना ही निजी है जितनी उसके पीछे मौजूद फ़ाइल:

chmod 600 db_password.txt

VPS पर व्यावहारिक मध्य मार्ग

कई self hosted images _FILE variables का समर्थन नहीं करतीं, इसलिए environment variables ही एकमात्र विकल्प हैं। एकल administrator VPS पर वास्तविक लक्ष्य यह है कि values आपके project directory की ऐसी file में न रहें जिसे सभी पढ़ सकें, और वे 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 सेट करता है। इसलिए ऐसा कोई समय नहीं रहता जब उसे हर व्यक्ति पढ़ सके। इसका स्वामित्व root के पास होता है, इसलिए उस server का non root user इसे नहीं पढ़ सकता। हालांकि, जो भी docker चला सकता है, वह container से value पढ़ सकता है। *.env और .env को .gitignore में जोड़ें। इसके बजाय एक app.env.example commit करें, जिसमें key names हों और values खाली हों। Commit किया गया password बदला हुआ password होता है।

किसी value को rotate करने का अर्थ service को restart करना है। Environment variables को container process शुरू होने पर केवल एक बार पढ़ा जाता है। इसलिए file में बदलाव तब तक प्रभावी नहीं होता, जब तक आप docker compose up -d --force-recreate db नहीं चलाते। यही pattern VPS पर HTTPS के पीछे n8n guide में भी इस्तेमाल किया गया है, जहां encryption key compose file के बाहर रहती है।

प्रत्येक environment के लिए configuration अलग करना

Compose डिफ़ॉल्ट रूप से project directory से .env पढ़ता है। --env-file का उपयोग करके इसे किसी अन्य स्थान पर निर्देशित करें।

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

कई files क्रम से पढ़ी जाती हैं और बाद वाली files, पहले वाली files की settings को override करती हैं। गैर-गोपनीय defaults को committed file में रखें और secrets को ऐसी file में रखें जो कभी server से बाहर न जाए। यही बात env_file: पर भी लागू होती है। किसी duplicate key के लिए सूची में सबसे अंत में दी गई file की value प्रभावी होती है।

FAQ

कंटेनर के अंदर मेरी .env फ़ाइल को अनदेखा क्यों किया जा रहा है?

इसे अनदेखा नहीं किया जा रहा है। .env फ़ाइल केवल compose फ़ाइल में ${NAME} प्लेसहोल्डर को प्रतिस्थापित करती है। यह कंटेनर के अंदर कभी भी variables सेट नहीं करती। मान को कंटेनर में भेजने के लिए इसका संदर्भ दें: 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 दोनों स्थानों पर सेट है, तो env_file में दिया गया मान बिना किसी सूचना के उपयोग नहीं किया जाता।

Compose द्वारा उपयोग किया जाने वाला अंतिम मान कैसे देखूँ?

पूरी तरह resolved compose फ़ाइल को सभी interpolation के साथ प्रिंट करने के लिए docker compose config चलाएँ। पहले से चल रहे कंटेनर के लिए, docker inspect <container> --format '{{json .Config.Env}}' यह दिखाता है कि उसके process को वास्तव में क्या प्राप्त हुआ।

क्या Compose secrets encrypted होते हैं?

नहीं। File-based secret कंटेनर में /run/secrets/<name> पर plain file के रूप में mount किया जाता है, और source file host disk पर unencrypted रहती है। इसका लाभ encryption नहीं, बल्कि scope है: मान container environment से बाहर, docker inspect output से बाहर, और उन crash dumps से बाहर रहता है जो environment प्रिंट करते हैं।

क्या मैं env फ़ाइल में quotes और spaces का उपयोग कर सकता हूँ?

KEY=value with spaces का उपयोग करें और quotes हटा दें। Compose पूरी line के शेष भाग को मान के रूप में लेता है, इसलिए quotes आमतौर पर मान में literal characters बन जाते हैं। = के आसपास कभी spaces न रखें, क्योंकि तब key में trailing space शामिल हो जाती है और कोई भी मान उससे match नहीं करता।