دليل عملي

أذونات مجلدات Docker: الإصلاح في 3 أوامر

النشر10 دقائق للقراءةعدد الخطوات: 10

التطبيق يعمل، الحاوية تشتغل، لكن السجلات تُظهر ‏`Permission denied`‏ ولا يُحفظ أي شيء. هذه المشكلة تصيب تقريباً كل التطبيقات المُستضافة ذاتياً عند تثبيت مجلد من المضيف داخل ‏Docker‏. السبب دائماً واحد: معرّف المستخدم ‏(UID)‏ الذي يعمل داخل الحاوية لا يتطابق مع مالك المجلد على المضيف. يشرح هذا الدليل الآلية ويقدّم أوامر التشخيص والإصلاح المناسب لكل حالة — دون تشغيل الحاويات بصلاحيات ‏root‏ أبداً.

المحتويات· الآلية: لماذا يرفض Docker الكتابة1/9
  1. 01الآلية: لماذا يرفض Docker الكتابة
  2. 02التطبيقات الأكثر تأثراً ومعرّفات المستخدم الخاصة بها
  3. 03التشخيص: تحديد المشكلة في أقل من دقيقتين
  4. 04الإصلاح حالة بحالة: chown على مجلد المضيف
  5. 05الأنواع المختلفة: bind-mounts والمجلدات المُسمّاة و user:
  6. 06حالات NFS والتثبيتات البعيدة
  7. 07مقارنة طرق الإصلاح
  8. 08استكشاف الأخطاء: 4 أخطاء كلاسيكية مع رسائلها الدقيقة
  9. 09الخلاصة

الآلية: لماذا يرفض Docker الكتابة

‏Docker‏ يشارك نواة ‏Linux‏ للمضيف. عند تثبيت مجلد من المضيف ‏(bind-mount)‏، يطبّق نظام الملفات قواعد أذونات ‏POSIX‏ نفسها. ملف يملكه ‏UID 1000‏ على المضيف يبقى تحت ملكية ‏UID 1000‏ بغض النظر عن الاسم — سواء كان ‏alice‏ على المضيف أو ‏paperless‏ داخل الحاوية. إذا كانت العملية في الحاوية تعمل بـ‏UID 472‏ والمجلد يملكه ‏root (UID 0)‏، تُرفض الكتابة — حتى لو استخدمت ‏chmod 755‏.

الفخ الكلاسيكي: تُنشئ المجلد بجلسة ‏SSH‏ الخاصة بك ‏(UID 1000)‏، ثم تُشغّل حاوية ‏Grafana‏ التي تعمل بـ‏UID 472‏. يحاول ‏Grafana‏ الكتابة في ‏/var/lib/grafana‏ المُثبَّت من ‏/opt/grafana/data‏ — الذي يملكه مستخدم ‏SSH‏. النتيجة: ‏GF_PATHS_DATA='/var/lib/grafana' is not writable.

التطبيقات الأكثر تأثراً ومعرّفات المستخدم الخاصة بها

تؤثر مشكلات أذونات Docker بصورة رئيسية على التطبيقات التي تعمل بـUID محدد يختلف عن UID المضيف.

  • ‏Paperless-ngx‏ — ‏UID 1000‏ (المستخدم ‏paperless‏): يدير مجلدات ‏consume‏ و‏export‏ و‏media‏ و‏data
  • ‏Grafana‏ — ‏UID 472‏ (المستخدم ‏grafana‏): يكتب قاعدة بيانات ‏SQLite‏ والإضافات في ‏/var/lib/grafana
  • ‏Nextcloud‏ (صورة ‏Debian‏) — ‏UID 33‏ (المستخدم ‏www-data‏): مجلد البيانات والإعدادات والسجلات
  • ‏Immich‏ — ‏UID 1000‏ (المستخدم ‏node‏): مكتبة الصور والصور المصغّرة وقاعدة بيانات الذكاء الاصطناعي
  • ‏Gitea‏ — ‏UID 1000‏ (المستخدم ‏git‏): المستودعات ومفاتيح ‏SSH‏ والسجلات وقاعدة بيانات ‏SQLite‏ الافتراضية

التشخيص: تحديد المشكلة في أقل من دقيقتين

قبل الإصلاح، تأكد أن المشكلة فعلاً تخص الأذونات وحدد ‏UID‏ المعني. ثلاثة أوامر تكفي.

  1. قراءة رسالة الخطأ الدقيقة

    راجع سجلات الحاوية المُشكِلة:

    docker logs <اسم-الحاوية> 2>&1 | grep -i 'permission\|denied\|cannot\|mkdir'

    رسالة ‏permission denied‏ أو ‏cannot create directory‏ تؤكد التشخيص.

  2. تحديد UID العملية داخل الحاوية

    docker exec <اسم-الحاوية> id

    مثال على الناتج: ‏uid=472(grafana) gid=0(root)‏. لاحظ ‏UID‏ — هنا ‏472‏.

  3. التحقق من مالك مجلد المضيف

    ls -ln /opt/grafana/data

    ناتج ‏drwxr-xr-x 2 0 0 ...‏ يعني أن المجلد يملكه ‏root (UID 0)‏. ‏UID 472‏ لديه فقط صلاحيات «other» — القراءة والتنفيذ، لا الكتابة.

  4. استخدام stat للتشخيص الكامل

    stat /opt/grafana/data

    تحقق من سطري ‏Uid:‏ و‏Gid:‏. إذا أظهرا ‏(0/root)‏ بينما تعمل الحاوية بـ‏472‏، تأكدت المشكلة.

  5. فحص إعدادات الحاوية

    docker inspect <اسم-الحاوية> | grep -A5 'Mounts'

    يسرد هذا الأمر كل ‏bind-mounts‏ والمجلدات المُسمّاة النشطة.

الإصلاح حالة بحالة: chown على مجلد المضيف

الإصلاح الأساسي هو ‏chown‏ على مجلد المضيف نحو ‏UID‏ الذي تتوقعه الحاوية. إليك الأوامر للتطبيقات الأكثر شيوعاً.

  1. ‏Grafana‏ (UID 472)

    mkdir -p /opt/grafana/data
    chown -R 472:472 /opt/grafana/data

    في ‏compose.yml‏ الخاص بك:

    volumes:
      - /opt/grafana/data:/var/lib/grafana
  2. ‏Nextcloud‏ (UID 33، صورة Debian)

    mkdir -p /opt/nextcloud/{data,config,apps}
    chown -R 33:33 /opt/nextcloud/data
    chown -R 33:33 /opt/nextcloud/config

    تنبيه: صورة ‏Alpine‏ تستخدم ‏UID 82‏. تحقق بـ‏docker exec <حاوية> id www-data‏ إذا لم تكن متأكداً.

  3. ‏Paperless-ngx‏ (UID 1000)

    mkdir -p /opt/paperless/{consume,export,media,data}
    chown -R 1000:1000 /opt/paperless/consume
    chown -R 1000:1000 /opt/paperless/export
    chown -R 1000:1000 /opt/paperless/media
    chown -R 1000:1000 /opt/paperless/data
  4. ‏Immich‏ (UID 1000)

    mkdir -p /opt/immich/{library,thumbnails,encoded-video,profile}
    chown -R 1000:1000 /opt/immich

    تنبيه: متغيرات البيئة ‏PUID/PGID‏ لا تعمل مع صور ‏Immich‏ الرسمية.

  5. التحقق بعد الإصلاح

    ls -ln /opt/grafana/data

    يجب أن يُظهر ‏drwxr-xr-x 2 472 472 ...‏. ثم أعد تشغيل الحاوية:

    docker compose restart grafana
    docker logs grafana --tail 20

الأنواع المختلفة: bind-mounts والمجلدات المُسمّاة و user:

يعمل ‏chown‏ على مجلد المضيف لـ‏bind-mounts‏، لكن ‏Docker‏ يوفر مقاربات أخرى.

توجيه ‏user:‏ في ‏compose.yml‏. بعض الصور مُصمَّمة لقبول ‏UID‏ اعتباطي عبر ‏user:‏. هذا يتجنب ‏chown‏ إذا كان مجلدك يملكه مستخدم المضيف:

services:
  app:
    image: my-image
    user: "1000:1000"
    volumes:
      - /home/user/data:/app/data

هذه المقاربة تعمل فقط إذا كانت الصورة لا تتطلب ملفات داخلية بـ‏UID‏ محدد.

المجلدات المُسمّاة في Docker. مع مجلد ‏Docker‏ مُسمّى، يدير ‏Docker‏ المجلد تحت ‏/var/lib/docker/volumes/‏. عند أول كتابة، يُنشأ المجلد بأذونات عملية الحاوية — لا مشاكل أذونات عند بدء التشغيل، لكن ترحيل البيانات الموجودة يتطلب خطوة نسخ صريحة.

حالات NFS والتثبيتات البعيدة

تُضيف تثبيتات ‏NFS‏ طبقة تعقيد: يطبّق خادم ‏NFS‏ قواعد ‏UID‏ الخاصة به. إذا كان الخادم يُصدِّر مع ‏root_squash‏ (الافتراضي)، يُخفَّض وصول ‏root‏ من العميل إلى ‏nobody‏.

الحلول:
1. ضبط تصدير ‏NFS‏ بـ‏all_squash,anonuid=472,anongid=472‏ لـ‏Grafana‏.
2. استخدام ‏no_root_squash‏ فقط إذا كنت تتحكم كلياً في الشبكة (خطر أمني).
3. لـ‏CIFS/SMB‏، مرّر ‏uid=33,gid=33‏ في خيارات التثبيت لـ‏Nextcloud‏.

في ‏/etc/fstab‏:

//server/share /opt/nextcloud/data cifs uid=33,gid=33,credentials=/etc/cifs-creds,iocharset=utf8 0 0

مقارنة طرق الإصلاح

مرّر الجدول أفقيًا

الطريقةالمزاياالمخاطر / القيود
chown UID:GID على مجلد المضيفبسيطة وعالمية ومتوافقة مع جميع الصوريجب معرفة UID الدقيق؛ تحتاج إعادة التطبيق عند إعادة إنشاء المجلد
user: UID:GID في compose.ymlلا حاجة لـ chown؛ قابل للنقل بين المضيفينالصورة يجب أن تدعم UIDs اعتباطية؛ قد يكسر الملفات الداخلية
المجلدات المُسمّاة في Dockerتُدار الأذونات تلقائياً عند أول تشغيلأقل شفافية؛ ترحيل البيانات الموجودة أكثر تعقيداً
--privileged أو chmod 777يحل المشكلة فوراًخطر: يكشف المضيف وجميع العمليات؛ لا تستخدم أبداً في الإنتاج

استكشاف الأخطاء: 4 أخطاء كلاسيكية مع رسائلها الدقيقة

إليك أكثر أربعة أخطاء Docker شيوعاً المتعلقة بالأذونات، مع رسالة الخطأ الدقيقة وحلها.

  • ‏mkdir: cannot create directory '/var/lib/grafana/plugins': Permission denied‏ ← مجلد المضيف لا يملكه ‏UID 472‏. طبّق ‏chown -R 472:472 /opt/grafana/data‏.
  • ‏[Errno 13] Permission denied: '/usr/src/paperless/media'‏ ← ‏Paperless-ngx‏ لا يمكنه الكتابة في مجلد ‏media‏. تحقق أن ‏bind-mount‏ يملكه ‏UID 1000‏ على المضيف.
  • ‏Could not create lock file /var/lib/grafana/.~lock.grafana.db‏ ← ‏Grafana‏ يقرأ المجلد لكنه لا يستطيع الكتابة. مشكلة أذونات على الملفات الموجودة: احذف ملف القفل.
  • ‏chown: changing ownership of '/data': Operation not permitted‏ (عند بدء الحاوية) ← الصورة تحاول إصلاح الأذونات لكنها لا تعمل بـ‏root‏. نفّذ ‏chown‏ يدوياً على المضيف قبل تشغيل الحاوية.

‏SELinux‏ و‏AppArmor‏: العَلَمان ‏:z‏ و‏:Z‏ في ‏bind-mounts‏. على الأنظمة ذات ‏SELinux‏ النشط (‏CentOS‏، ‏RHEL‏، ‏Fedora‏)، قد يُحظر ‏bind-mount‏ حتى لو كانت أذونات ‏POSIX‏ صحيحة. ‏Docker‏ يوفر لاحقتين: ‏:z‏ يُعيد تسمية المحتوى للمشاركة بين حاويات متعددة، و‏:Z‏ للوصول الخاص. مثال: ‏- /opt/grafana/data:/var/lib/grafana:z‏. للتحقق: ‏ausearch -m AVC -ts recent | grep docker‏.

الخلاصة

‏Permission denied‏ في سجلات ‏Docker‏ ليس قدراً محتوماً. الحل في ثلاثة أوامر: ‏docker exec <حاوية> id‏ لمعرفة ‏UID‏، ثم ‏ls -ln <مجلد-المضيف>‏ للتأكد من المالك الحالي، ثم ‏chown -R <UID>:<GID> <مجلد-المضيف>‏ للإصلاح. القاعدة الذهبية: أنشئ مجلدات المضيف بالمالك الصحيح قبل تشغيل الحاوية، لا بعدها.

VPS جاهز للاستضافة الذاتية

انشر تطبيقات Docker على VPS من ServOrbit مع وصول root وIPv4 مخصصة ولقطات تلقائية. ابتداءً من ‏99 درهم/شهر‏.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة