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

> Sorun izin bitlerinde değil, UID eşleşmesinde: mount'un sahibi ile container kullanıcısının UID'si uyuşmuyor. Çözüm chmod 777 değil, sahipliği hizalamak.

- Soruldu: 2026-08-13
- Yanıtlandı: 2026-08-18
- Soran: Barış
- Etiketler: docker, güvenlik, laravel
- Kaynak: https://www.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. 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.

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 içeriği root sahipliğiyle doldurur; bind mount ise host dizininin sahipliğini olduğu gibi taşır. İkisinde de çözüm farklı.
3. **Entrypoint'te hedefli chown + drop.** 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 "$@"
```
4. **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.
5. **chmod 777'den kaçının.** 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 yeterli; yeni dosyaların grubunu korumak için dizine setgid bit'i (`chmod g+s`) verin.
6. **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.
