SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-10-13

Docker Compose .env, env_file ve secrets farkları

Docker Compose'ta .env, env_file ve environment farklarını, öncelik sırasını ve parolaların neden environment yerine secrets ile saklanması gerektiğini öğrenin.

İnsanların env dosyası olarak adlandırdığı üç şey

Docker Compose, kafa karıştırıcı derecede benzer isimlere sahip üç ayrı mekanizmaya sahiptir. .env dosyası, Compose YAML dosyasını okuduktan sonra ve herhangi bir doğrulama veya çalıştırma işlemi yapmadan önce, compose.yaml içindeki ${VARIABLE} yer tutucularını doldurur. env_file: özniteliği, anahtar/değer çiftlerinden oluşan bir dosyayı container ortamına yükler. environment: özniteliği ise değişkenleri doğrudan container üzerinde ayarlar ve compose dosyasına yazılır. Bunlar birbirinin yerine kullanılamaz; iki yöntem aynı anahtarı ayarladığında kazanan, belgelenmiş bir öncelik sırasına göre belirlenir.

Bu kılavuz, her birinin nasıl çalıştığını gösterir, öncelik sırasını çalıştırabileceğiniz bir komutla kanıtlar ve ardından daha önemli olan konuyu ele alır: ortam değişkenleri, docker inspect komutunu çalıştırabilen herkes tarafından okunabilir, bu nedenle parolalar bu değişkenlerde tutulmamalıdır. Compose dosyalarında genel olarak yeniyseniz, VPS üzerinde Docker Compose temelleri ile başlayıp yapılandırma için buraya geri dönün.

.env dosyası container için değil, compose dosyası içindir

Bir dizin oluşturun ve içine iki dosya yerleştirin.

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

Şimdi Compose'a gerçekte neyi ayrıştırdığını sorun.

docker compose config

Çıktı image: alpine:3.20 değerini gösterir. Yer tutucu kaybolmuştur çünkü interpolasyon, Compose dosyayı yüklediği sırada gerçekleşmiştir. Compose, .env değerini proje dizininde arar: eğer ayarladıysanız --project-directory ile belirtilen dizin, aksi takdirde -f ile iletilen ilk dosyanın bulunduğu dizin, o da yoksa mevcut çalışma dizininiz. YAML değerleri içinde bulduğu ${NAME} yer tutucularının yerine değerleri yerleştirir. Anahtarlar asla enterpole edilmez ve çift $$ kullanımı, yer değiştirme yerine düz bir dolar işareti üretir.

Ardından servisi çalıştırın.

docker compose run --rm demo

printenv ALPINE_TAG durumu 1 ile sonlanır ve hiçbir çıktı vermez. Değişken, container içinde mevcut değildir. Bu, en sık karşılaşılan yanlış anlaşılmadır: .env, compose dosyasını yapılandırır, süreci değil. İçinde POSTGRES_PASSWORD=hunter2 bulunan bir .env dosyası, compose dosyasının herhangi bir parçası ona referans vermediği sürece veritabanınız için hiçbir işlev görmez.

${NAME:-default}, değişken ayarlanmamış veya boş olduğunda bir yedek değer sağlar. ${NAME:?message} ise Compose'un başlamayı reddetmesini ve mesajınızı yazdırmasını sağlar; bu, güvenli bir varsayılan değeri olmayan bir değişken için en doğru tercihtir.

env_file, değişkenleri container içine yükler

env_file: özniteliği, içerikleri container ortam değişkenlerine dönüştürülecek bir veya daha fazla dosyayı tanımlar.

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

Bu komut from_env_file çıktısını verir. Dosya biçimi, her satırda bir tane olacak şekilde düz KEY=value satırlarından oluşur ve # karakteri yorum satırını başlatır. Bu bir shell betiği değildir, ancak Compose bunu birkaç shell benzeri kural ile ayrıştırır. Çevreleyen tırnak işaretleri kaldırılır, bu nedenle KEY="value" ve KEY=value aynı sonucu verir. Çift tırnaklı ve tırnaksız değerlerde ${...} yer tutucuları işlenirken, tek tırnaklı değerler olduğu gibi kullanılır. Bir export ön eki kabul edilir ancak gerekli değildir. = işaretinin etrafındaki boşluklar kırpılır. Dikkat edilmesi gereken nokta satır içi yorumlardır: tırnaksız bir değerde, bir boşluğu takip eden # karakteri yorumu başlatır, bu nedenle # içeren herhangi bir değeri tırnak içine alın.

Eksik bir env_file yolu bir hatadır ve Compose durur. Dosyanın bulunmaması meşru bir durumsa, onu isteğe bağlı olarak işaretleyin:

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

environment değişkenleri satır içi olarak ayarlar

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

Yukarıdaki eşleme biçimi ve - GREETING=from_environment kullanan liste biçimi olmak üzere iki sözdizimi kabul edilir. Bu iki biçim aynı şekilde çalışır. Her ikisi de fazladan bir özellik daha barındırır: değeri olmayan bir anahtar, değişkeni docker compose komutunu çalıştırdığınız kabuktan (shell) olduğu gibi aktarır. Liste biçiminde bu çıplak bir - GREETING, eşleme biçiminde ise iki noktadan sonra hiçbir şeyin gelmediği GREETING: ifadesidir.

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

Bu, from_my_shell çıktısını verir. Komutu, kabukta GREETING değişkenini ayarlamadan çalıştırırsanız Compose hiçbir şey ayarlamaz ve herhangi bir uyarı vermez. Sessiz aktarım hatalarının farkında olmak önemlidir; çünkü boş bir parola değişkeniyle başlayan bir servis genellikle başarıyla başlatılır ancak tamamen savunmasız kalır.

Hangisi öncelikli

Docker, öncelik sırasını en yüksekten başlayarak belgeler: önce komut satırındaki docker compose run -e, ardından değeri kabuğunuzdan veya bir env dosyasından enterpole edilen environment ya da env_file, sonra compose dosyasındaki düz environment, ardından env_file ve son olarak image içine yerleştirilmiş ENV yönergesi.

Günlük kullanım için kısa özet: environment:, env_file: değerine üstün gelir; komut satırındaki -e ise her ikisine de üstün gelir. Bunu tek bir dosyada doğrulayın.

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

İlk komut from_environment çıktısını verir. Bunun nedeni environment: değerinin app.env içindeki değerin üzerine yazmasıdır. İkinci komut from_cli çıktısını verir. Compose dosyasındaki hiçbir ayar komut satırındaki değerin üzerine yazmaz.

Bir container, yapılandırmanız hiç uygulanmamış gibi davranıyorsa tahminde bulunmayın. docker compose config, tamamen çözümlenmiş dosyayı yazdırır. docker compose config --environment ise Compose'un kullandığı enterpolasyon değişkenlerini yazdırır. "env dosyam yok sayılıyor" bildirimlerinin çoğunda aynı değer iki farklı düzeyde tanımlanmıştır.

Ortam değişkenleri neden sızar

environment: içinde bir parola ayarladığınızda, bu parola container yapılandırmasında disk üzerinde saklanır ve docker grubundaki tüm kullanıcılar tarafından görülebilir.

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

Çıktı, "DB_PASSWORD=hunter2" değerini düz metin olarak içerir. Üç farklı yol daha aynı değeri açığa çıkarır. docker compose config bu değeri terminale yazdırır; destek forumlarına yapıştırılan veriler genellikle bu şekilde sızar. Ebeveyn süreç, çocuk süreçleri kasıtlı olarak farklı bir ortamla başlatmadığı sürece, çocuk süreçler değişkeni varsayılan olarak devralır. PID 1 ile aynı kullanıcı haklarına sahip olan veya CAP_SYS_PTRACE yetkisine sahip bir süreç, bu değeri /proc/1/environ üzerinden okuyabilir. Her şeyin root olarak çalıştığı bir container içinde bu, tüm süreçler anlamına gelir. PID 1 root olarak çalışırken, yetkisiz bir kullanıcıyla çalışan uygulama bu dosyaya erişmeye çalıştığında izin hatası alır; ancak uygulama yine de değişkeni kendi ortamında tutmaya devam eder. Ayrıca, uygulama çökme yöneticileri genellikle tüm ortamı bir günlüğe veya hata raporuna dökebilir.

docker grubuna üyelik, ana makinede (host) fiilen root yetkisi anlamına gelir; dolayısıyla bu, güvenebileceğiniz bir ayrıcalık sınırı değildir. VPS üzerinde en düşük ayrıcalıklı kullanıcı hesapları hakkındaki rehber, bu grubun neden paylaşımlı her sunucuda kısıtlanması gerektiğini açıklamaktadır.

Compose secret değerini bir dosyada tutar

Compose, dosya tabanlı secret'ları destekler. Değer, ortama aktarılmak yerine container içine dosya olarak mount edilir.

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 içinde /run/secrets/db_password yoluna mount edilir. Eğik çizgiden sonraki ad, üst düzey secrets: bloğundaki secret adıdır.

_FILE son eki, postgres, mysql ve mariadb dahil Docker Official Images tarafından kullanılan bir kuraldır. Bu entrypoint script'leri VARNAME_FILE değerini kontrol eder, dosyayı okur ve içeriğini kullanır. Bu bir Docker özelliği değildir. Bu nedenle yalnızca image bunu uyguluyorsa çalışır. SOMETHING_FILE değerinin dikkate alınacağını varsaymadan önce image belgelerini kontrol edin. Bunu desteklemeyen uygulamalar, başlangıçta dosyayı kendileri okuyabilir. Alternatif olarak yolu aktarabilir ve işlemi kendi entrypoint'inize yaptırabilirsiniz.

Çalışan container içinden doğrulayın:

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

İlk komut parolayı yazdırır. İkinci komut hiçbir şey yazdırmaz, çünkü değer ortama hiç aktarılmamıştır. Amaç tam olarak budur: Bu container üzerindeki docker inspect yalnızca zararsız yolu gösterir.

Secret, arkasındaki dosya kadar gizli olduğundan host üzerindeki kaynak dosyayı koruyun:

chmod 600 db_password.txt

VPS üzerinde uygulanabilir orta yol

Birçok self-hosted imaj _FILE değişkenlerini desteklemez. Bu nedenle içeriye geçiş için tek yol ortam değişkenleridir. Tek yöneticili bir VPS'te gerçekçi hedef, değerlerin proje dizininde herkes tarafından okunabilen bir dosyada bulunmasını önlemek ve bunları git dışında tutmaktır.

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 dosyayı, izinleri baştan ayarlanmış şekilde oluşturur. Böylece dosyanın herkes tarafından okunabildiği bir zaman aralığı oluşmaz. Dosyanın sahibi root hesabıdır. Bu nedenle makinedeki root olmayan bir kullanıcı dosyayı okuyamaz. Ancak docker çalıştırabilen herkes değeri yine de container içinden okuyabilir. *.env ve .env satırlarını .gitignore dosyasına ekleyin. Bunun yerine anahtar adlarını boş değerlerle içeren bir app.env.example dosyasını commit edin. Commit edilmiş bir parola değiştirilmiş parola kabul edilir.

Bir değeri değiştirmek servisin yeniden başlatılmasını gerektirir. Ortam değişkenleri container işlemi başlatıldığında bir kez okunur. Bu nedenle dosyayı düzenlemek, docker compose up -d --force-recreate db çalıştırılana kadar hiçbir şeyi değiştirmez. Bu, VPS üzerinde HTTPS arkasında n8n kılavuzunda kullanılan yöntemin aynısıdır. Bu yöntemde şifreleme anahtarı compose dosyasının dışında tutulur.

Ortama göre yapılandırmayı ayırma

Compose, varsayılan olarak .env dosyasını proje dizininden okur. --env-file ile başka bir konum belirtilebilir.

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

Birden çok dosya sırayla okunur ve sonraki dosyalardaki değerler önceki değerleri geçersiz kılar. Gizli olmayan varsayılan değerler sürüm denetimine alınan bir dosyada, gizli bilgiler ise sunucudan hiçbir zaman çıkarılmayan bir dosyada tutulmalıdır. Aynı durum env_file: için de geçerlidir; yinelenen bir anahtar için listelenen son dosyanın değeri geçerli olur.

FAQ

.env dosyam container içinde neden yok sayılıyor?

Dosya yok sayılmaz. .env dosyası, compose dosyasındaki ${NAME} yer tutucularının yerine geçer ve ayrıca COMPOSE_PROJECT_NAME veya COMPOSE_FILE gibi Compose'un kendi değişkenlerini ayarlayabilir. Bu dosya, container içindeki değişkenleri asla ayarlamaz. Değeri container içine aktarmak için environment: { KEY: "${NAME}" } ile referans verin veya bunun yerine env_file: ./that-file.env kullanın.

environment mı env_file'ı geçersiz kılar, yoksa tam tersi mi?

environment: önceliklidir. Docker'ın belgelenmiş öncelik sırasına göre environment niteliği, env_file niteliğinin üzerindedir; her ikisi de komut satırındaki docker compose run -e değerinin altındadır. Bir anahtar her iki yerde de tanımlanmışsa, env_file içindeki değer sessizce göz ardı edilir.

Compose'un kullanacağı nihai değeri nasıl görebilirim?

Tüm interpolasyon uygulanmış, tamamen çözümlenmiş compose dosyasını yazdırmak için docker compose config komutunu çalıştırın. Hali hazırda çalışan bir container için docker inspect <container> --format '{{json .Config.Env}}', sürecin tam olarak neyi aldığını gösterir.

Compose secret'ları şifreli midir?

Hayır. Dosya tabanlı bir secret, container içine /run/secrets/<name> yolunda düz bir dosya olarak mount edilir ve kaynak dosya ana makine diskinde şifrelenmemiş halde durur. Sağladığı fayda şifreleme değil, kapsamdır: değer, container ortamının dışında, docker inspect çıktısının dışında ve ortam değişkenlerini yazdıran hata dökümlerinin dışında tutulur.

env dosyasında tırnak işareti ve boşluk kullanabilir miyim?

Evet. Compose, çevreleyen tırnak işaretlerini kaldırır; bu nedenle KEY="value with spaces" ve KEY=value with spaces ifadelerinin her ikisi de value with spaces sonucunu verir. Değer, interpolasyona uğramaması gereken bir $ içeriyorsa tek tırnak kullanın. # karakterini içeren her değeri tırnak içine alın; çünkü tırnak kullanılmadığında bu karakter bir yorum satırı başlatır. = etrafındaki boşluklar kırpılır, bu nedenle KEY = value ifadesi yine de KEY değerini ayarlar.

Bu yazı işinize yaradı mı?