# Container'ı non-root çalıştırınca mount edilen storage dizinine yazamıyorum, izinleri nasıl çözerim?

> Kullanıcıyı build-time `ARG UID` ile sabitleyin, `COPY --chown` kullanın, named volume'de entrypoint yalnız `storage` ve `bootstrap/cache`'i chown etsin.

- Soruldu: 2026-08-13
- Yanıtlandı: 2026-08-18
- Soran: Barış
- Etiketler: docker, guvenlik, laravel
- Kaynak: https://muhammetsafak.com/tr/sor-bakalim/containeri-non-root-calistirinca-mount-edilen-storage-dizinine-yazamiyorum-izinleri-nasil/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**Soru:** Laravel uygulamamı Docker'da çalıştırıyorum ve güvenlik için image'ı root yerine kendi oluşturduğum bir kullanıcıyla (non-root) çalıştırmaya geçtim. Ama bunu yaptıktan sonra `storage/` altına yazma işlemleri patlamaya başladı: log yazamıyor, cache ve session dosyaları oluşmuyor, sürekli "Permission denied" alıyorum.

Kurulumum şöyle: `php:8.3-fpm-alpine` tabanlı bir image, uygulama kodu image'ın içinde, ama `storage/` dizinini kalıcılık için bir volume olarak mount ediyorum. Container root iken hiç sorun yoktu. Non-root kullanıcıda izinleri, `chmod 777` yapmadan, doğru şekilde nasıl çözerim?


Kısa cevap: Sorun izin bitlerinde değil, UID eşleşmesinde.

## Kısa cevap

Container'daki kullanıcının sayısal UID'si, mount edilen dizinin sahibiyle uyuşmuyor; root iken çalışmasının sebebi de root'un (UID 0) her şeye yazabilmesiydi. Çözüm `chmod 777` değil, sahipliği hizalamak. İmajı non-root ve mümkün olduğunca dar kurmanın diğer yüzünü [çok aşamalı build ve distroless kaydında](/tr/sor-bakalim/docker-imaj-boyutunu-multi-stage-ve-distroless-ile-kucultmek/) ele almıştım.

## Neden

1. **Kök neden: UID, kullanıcı adı değil.** Linux izinlerinde önemli olan sayısal UID/GID'dir. Image'daki `app` kullanıcısı UID 1000 olabilir; ama mount ettiğiniz dizin host'ta başka bir UID'ye aitse kernel yazmayı reddeder. İsim eşleşmesi hiçbir şey ifade etmez.

2. **Named volume mü, bind mount mu?** Named volume Docker tarafından yönetilir ve ilk oluşumda image'daki mount noktasının sahiplik/izinlerini kopyalar (çoğunlukla root çıkar ama bu garanti değildir); bind mount ise host dizininin sahipliğini olduğu gibi taşır. İkisinde de çözüm farklı.

3. **`chmod 777` neden çözüm değil.** Bu bir güvenlik gerilemesidir ve non-root'a geçme amacınızı boşa çıkarır. Group-writable (`g+w`) izin ile doğru grup üyeliği zaten yeterlidir; sorun izin bitlerinin darlığı değil, sahipliğin yanlış yerde olmasıdır.

## Ne yapmalı

1. **Bind mount'ta build-time UID'yi hizalayın.** Dockerfile'da `ARG UID`/`ARG GID` ile kullanıcıyı host'unuzun UID'siyle oluşturun, kodu `COPY --chown=app:app` ile kopyalayın. Böylece entrypoint hilesine bile gerek kalmadan sahiplik baştan doğru olur. Yeni dosyaların grubunu korumak için dizine setgid bit'i (`chmod g+s`) verin.

2. **Named volume'de entrypoint'te hedefli chown + drop yapın.** Container'ı root olarak başlatın, yalnızca yazılabilir olması gereken dizinleri chown edin, sonra kullanıcıya düşün:

   ```bash
   #!/bin/sh
   # entrypoint (root ile başlar, sonra app'e düşer)
   chown -R app:app storage bootstrap/cache
   exec su-exec app "$@"
   ```

3. **Kalıcı state'i doğru yere koyun.** Birden çok replica çalıştıracaksanız `storage/`'ı paylaşımlı bir dosya sistemi üzerinden değil, session/cache için Redis'e ve dosyalar için S3 gibi bir object storage'a taşıyın; volume izin derdi tamamen kaybolur.

**Sonuç:** Ben olsam build-time `ARG UID` ile kullanıcıyı sabitler, `COPY --chown` kullanır ve named volume'ler için entrypoint'te yalnızca `storage` ve `bootstrap/cache`'i chown edip `su-exec` ile app'e düşerdim. Uzun vadede ise kalıcı veriyi mümkün olduğunca S3/Redis'e taşıyıp container'ı gerçekten stateless tutardım.

## İlgili Yazılar

- [Self-hosted CI/CD runner'larını nasıl izole eder, her çalışmadan sonra temizlenen (ephemeral) ortamı nasıl kurarım?](https://muhammetsafak.com/tr/sor-bakalim/self-hosted-ci-cd-runner-izolasyonu-ve-ephemeral-ortam/) — Sor Bakalım
- [Birçok modele bağlanan yorumlar için polymorphic ilişki mi yoksa ayrı tablolar mı; index ve foreign key açısından hangisi daha sağlıklı?](https://muhammetsafak.com/tr/sor-bakalim/bircok-modele-baglanan-yorumlar-polymorphic-iliski-ayri-tablolar/) — Sor Bakalım
- [Container'daki Go worker'ım SIGTERM almıyor ve graceful kapanmıyor, bu bir PID 1 sorunu mu?](https://muhammetsafak.com/tr/sor-bakalim/containerdaki-go-workerim-sigterm-almiyor-pid-1-sorunu/) — Sor Bakalım
