SSD Nodes Learn Hosting plans →
الأدلة Matt Connorبقلم Matt Connor

ما دور PUID وPGID في Docker Compose؟

افهم لماذا تظهر ملفات bind mount بملكية 911:911: فـPUID وPGID اصطلاح في صور linuxserver.io، وليسا إعدادين يقرأهما Docker، واعرف طريقة إصلاحهما.

ما هي PUID و PGID فعلياً

تُعد PUID و PGID متغيري بيئة تقرأهما صور حاويات معينة عند بدء التشغيل. لا ينظر Docker نفسه إليهما أبداً. إنهما اصطلاح تستخدمه صور linuxserver.io وعدد قليل من الصور الأخرى، لذا فإن أي صورة لم تُكتب لقراءتهما ستتجاهلهما بصمت.

داخل صورة linuxserver.io، يوجد مستخدم يسمى abc، يتم إنشاؤه وقت البناء بمعرف مستخدم (UID) 911 ومعرف مجموعة (GID) 911. تبدأ الحاوية بصلاحيات root، وتُشغّل نصوصها البرمجية الأولية، ويقوم أحد هذه النصوص بإعادة ترقيم ذلك المستخدم قبل بدء التطبيق:

groupmod -o -g "${PGID}" abc
usermod -o -u "${PUID}" abc

يسمح العلم -o باستخدام معرف مستخدم مستخدم بالفعل في مكان آخر. بعد ذلك، تتخلى عملية التهيئة عن الصلاحيات وتُشغّل التطبيق بصفتها abc. لذا، يمرر Docker المتغير PUID=1000 إلى داخل الحاوية كأي متغير بيئة آخر ولا يتخذ أي إجراء بشأنه. يقوم المتغير بإعادة ترقيم مستخدم داخل الحاوية قبل بدء التطبيق، مما يعني أنه في حالة استخدام daemon قياسي بصلاحيات root دون إعادة تعيين مساحة أسماء المستخدمين (user namespace remapping)، فإن الملفات المنشأة حديثاً تظهر على القرص بملكية المعرف 1000. الكتابة في ملف موجود وقابل للكتابة لا تغير مالكه. يقوم Docker الذي يعمل بدون صلاحيات root (Rootless Docker) بإزاحة هذا الرقم، كما هو موضح أدناه. اترك PUID دون تعيين وسيحافظ abc على القيمة 911، وهذا هو السبب في أن مجلد الربط (bind mount) غير المهيأ يمتلئ بملفات يملكها 911:911.

احصل على رقميك باستخدام id

نفّذ هذا الأمر على المضيف، بصفتك المستخدم الذي يملك أدلة البيانات:

id
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),988(docker)

uid هو PUID الخاص بك وgid هو PGID الخاص بك. بالنسبة للسكربتات، يقوم id -u وid -g بطباعة الأرقام مجردة. في معظم صور VPS الجديدة، يكون حساب المستخدم البشري الأول هو 1000:1000، لكن لا تفترض ذلك. يعتمد التخصيص على الحسابات والإعدادات الموجودة: قد يخصص الخادم المُعاد بناؤه الرقم 1000 مجدداً، بينما يحصل الحساب اللاحق على معرف متاح أعلى. إذا كانت خدماتك تعمل تحت حساب خدمة مخصص بدلاً من مستخدم تسجيل الدخول الخاص بك، نفّذ id thatuser واستخرج الأرقام من هناك.

لماذا تظهر ملفاتك بالمعرف 911:911

يطبع ls -l معرفاً رقمياً بدلاً من الاسم عندما لا يطابق هذا المعرف أي حساب على المضيف. إذا لم يطابق أي حساب على المضيف المعرف UID 911، فلن يوجد اسم ليتم طباعته. استخدم ls -ln لرؤية الأرقام في كل مرة وإزالة الغموض:

ls -ln /srv/appdata/sonarr
drwxr-xr-x 2 911 911 4096 Aug  7 09:12 Backups
-rw-r--r-- 1 911 911  512 Aug  7 09:12 config.xml

تطابق هذه المخرجات الإعدادات الافتراضية المدمجة في الحاوية، لكن الملفات الموجودة وحدها لا تثبت هوية المستخدم الذي يعمل التطبيق بصلاحياته حالياً. الملف config.xml في تلك القائمة هو أيضاً الملف الذي يحمل إعدادات المصادقة، وهو أمر مهم في المرة الأولى التي تفتح فيها واجهة الويب وتجد أن Sonarr و Radarr لا يأتيان باسم مستخدم أو كلمة مرور افتراضية. تأكد من ذلك من داخل الحاوية بدلاً من التخمين:

docker exec sonarr id abc
docker compose logs sonarr | head -n 25

يطبع نظام تهيئة linuxserver نتيجته في سجل بدء التشغيل كسطرين:

User UID:    911
User GID:    911

إذا كانت تلك الأسطر تقرأ 911 بعد تعيينك لـ PUID=1000 في ملف Compose الخاص بك، فهذا يعني أن الحاوية قيد التشغيل لا تستخدم القيمة التي حددتها. السبب المعتاد هو أنك قمت بتعديل docker-compose.yml ثم نفذت docker compose restart، والذي يعيد استخدام الحاوية الموجودة ببيئتها الأصلية. تتطلب تغييرات البيئة تنفيذ docker compose up -d، الذي يعيد إنشاء الحاوية. السبب الآخر متعمد: عندما تعمل الصورة في وضع القراءة فقط أو وضع غير الجذر (non-root)، يتخطى نظام التهيئة إعادة الترقيم تماماً، حتى لو كان المتغير موجوداً في الحاوية. في وضع القراءة فقط، يبلغ الشعار عن المعرف غير المتغير لـ abc؛ وفي وضع غير الجذر، يبلغ عن مالك /run.

لماذا لا يمكنك حذف ملف كتبه الـcontainer

تقارن النواة الأرقام، وليس الأسماء. تعمل الصدفة لديك باستخدام UID 1000. ويعود الملف إلى UID 911. أما الدليل الذي يحتويه فهو drwxr-xr-x ويعود أيضاً إلى 911، لذلك يحصل كل من المجموعة والآخرين على صلاحيتَي القراءة والتنفيذ، من دون الكتابة. يتطلب حذف ملف صلاحية الكتابة على دليله، وليس على الملف نفسه، لذلك تحصل على النتيجة التالية حتى عندما يبدو الملف نفسه غير ضار:

rm: cannot remove '/srv/appdata/sonarr/config.xml': Permission denied

يواجه الـcontainer الذي يكتب المشكلة نفسها من الجهة الأخرى. إذا كان دليل المضيف يعود إلى مستخدمك وبصلاحيات 755، بينما يعمل التطبيق باستخدام 911، تفشل أول عملية كتابة له مع Permission denied، ويعرض التطبيق ذلك بصياغته الخاصة. في تطبيق .NET مثل Sonarr أو Radarr، يظهر الخطأ على شكل UnauthorizedAccessException: Access to the path '/data/downloads' is denied. تخبرك سلسلة الصلاحيات الموجودة قبل اسم الملف بأي مجموعة من مجموعات الصلاحيات الثلاث تُطبَّق عليك فعلياً، كما أن قراءة drwxr-xr-x بشكل صحيح هي ما يحوّل هذا الخطأ من أمر غامض إلى نتيجة واضحة.

هذه مشكلة خاصة بـ bind mount. عندما ينشئ Docker named volume فارغاً ويربطه بمسار موجود في image، ينسخ محتويات ذلك المسار إلى volume، بما في ذلك الملكية وبتات الصلاحيات، لذلك يجد التطبيق دليلاً يملكه مسبقاً. لا يحصل bind mount على هذه المعالجة: إذ يربط Docker دليل المضيف كما هو تماماً. وهذا الاختلاف أحد الأسباب العملية لمعرفة متى يكون bind mount أفضل من named volume ومتى لا يكون كذلك.

إصلاح دليل يحتوي بالفعل على أخطاء

يؤدي تعيين PUID و PGID إلى تغيير سلوك التطبيق من الآن فصاعداً. لا يقوم هذا الإجراء بإصلاح ملكية الملفات الموجودة مسبقاً على القرص بأثر رجعي، على الرغم من أن عملية التهيئة (init) تصحح الملكية في مسارات محددة موصوفة أدناه. أوقف الحزمة (stack)، وصحح الملكية بنفسك، ثم ابدأ تشغيلها مجدداً:

docker compose down
sudo chown -R 1000:1000 /srv/appdata/sonarr
docker compose up -d

استخدم sudo chown -R "$(id -u):$(id -g)" /srv/appdata/sonarr إذا كنت تفضل عدم كتابة الأرقام يدوياً. نفذ هذا الإجراء بينما تكون الحاوية متوقفة، لأن التطبيق الذي يعمل في منتصف عملية كتابة أثناء تنفيذ أمر chown متكرر قد ينتهي به الأمر بشجرة أدلة مصححة جزئياً، مما يسبب جولة ثانية مربكة من الأخطاء.

ما لا تعالجه قيم PUID و PGID

هذا هو الجزء الذي يقع فيه المستخدمون الذين نفذوا كل الخطوات بشكل صحيح. يقوم نص إعداد المستخدم في صورة linuxserver الأساسية بتغيير ملكية (chown) ثلاثة مسارات عند بدء التشغيل وهي: /app و /config و /defaults. لا تتضمن هذه القائمة مسارات وسائط التخزين (media mounts) الخاصة بك. يتم تمرير /data و /downloads و /tv إلى التطبيق دون أي تعديل، لذا إذا كانت ملكية تلك المسارات على المضيف لا تسمح لمستخدم الحاوية بالكتابة، فستبدأ الحاوية بشكل سليم، وتطبع معرف المستخدم (UID) الصحيح في شعارها، ثم تفشل عند أول عملية استيراد.

هذا هو السلوك الصحيح. فإجراء عملية chown متكررة على مكتبة وسائط بحجم اثني عشر تيرابايت عند كل تشغيل للحاوية سيكون كارثياً. هذا يعني أن مسؤولية أدلة الوسائط تقع على عاتقك، وهي المسارات التي تحدث فيها مشاكل الصلاحيات فعلياً. ولأن هذا النوع من الفشل يظهر بصمت في سجلات التطبيق بعد ساعات من ظهور الحاوية بحالة سليمة، فإن إجراء اختبار كتابة دوري مرتبط بـ خدمة ntfy على خادمك الخاص (VPS) لإرسال تنبيهات إلى هاتفك يعد وسيلة غير مكلفة لاكتشاف المشكلة قبل أن تكتشفها بنفسك بعد أسبوع من فقدان الحلقات.

ثلاث طرق للتحكم في المستخدم، ومتى تُستخدم كل منها

متغيرات البيئة PUID و PGID

تعمل هذه الطريقة فقط مع الصور التي تقرأ هذه المتغيرات ضمن نقطة الدخول (entrypoint). تحظى هذه الطريقة بشعبية لأن الحاوية تبدأ بصلاحيات root، وتُجري إعداداتها الخاصة، وتُصلح /config، ثم تتخلى عن الصلاحيات لاحقاً. تظل Docker Mods ونصوص التهيئة المخصصة تعمل بشكل طبيعي. العيب هو أنك تعتمد على اتفاقية برمجية بدلاً من ميزة أصلية في المنصة، كما أن أسماء المتغيرات ليست موحدة عبر المشاريع المختلفة.

المفتاح user: في Compose

هذه ميزة حقيقية في Docker وتعمل مع جميع الصور، لأن بيئة تشغيل الحاوية تطبقها قبل تنفيذ كود الصورة نفسه:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    user: "1000:1000"

لا تعمل العملية بصلاحيات root أبداً، ولا حتى للحظة واحدة، وهو ما يمثل مكسباً أمنياً حقيقياً. في المقابل، يؤدي هذا إلى تعطيل أي شيء في نقطة الدخول كان يحتاج لصلاحيات root. في صور linuxserver، يدعم المشروع هذا الخيار على أساس "بذل الجهد المعقول" وفقط للصور التي تم اختبارها، والتحذيرات محددة: تتوقف PUID و PGID عن التأثير، ولن تعمل Docker Mods، ولن تعمل الخدمات المخصصة، وتصبح أنت المسؤول عن الصلاحيات في كل مجلد مثبت (mounted volume). النمط الموثق لديهم يقرن هذا العلم بـ /run قابل للكتابة:

user: 1000:1000
tmpfs:
  - /run:uid=1000,gid=1000,exec
security_opt:
  - no-new-privileges=true

هناك أثر جانبي شكلي يفاجئ المستخدمين. إذا كان هناك user: رقمي لا يملك إدخالاً مطابقاً في ملف /etc/passwd الخاص بالحاوية، فإن الأدوات داخل الحاوية ستُبلغ عن whoami: cannot find name for user ID 1000. المعرّف (ID) صالح والوصول إلى الملفات يعمل بشكل طبيعي، فقط البحث عن اسم المستخدم هو الذي يفشل.

وضع Rootless Docker

يقوم Rootless Docker بتشغيل الـdaemon نفسه كمستخدم غير متميز (unprivileged user)، لذا يعمل الـdaemon والحاويات بدون صلاحيات root على المضيف. يغير هذا حسابات الملكية تماماً. يتم تعيين UID 0 في الحاوية إلى UID المستخدم الذي يشغل Rootless Docker على المضيف، ويتم تعيين UID الحاوية n لأي n قيمته 1 أو أكثر إلى subuid + (n - 1)، حيث subuid هو أساس النطاق المخصص لك في /etc/subuid؛ وتتبع معرّفات المجموعات (GIDs) نفس القاعدة باستخدام /etc/subgid. يتوقع Docker وجود 65,536 معرّفاً فرعياً على الأقل هناك.

أعد قراءة هذا التعيين، لأنه يعكس النصيحة المعتادة. في وضع Rootless Docker، الحاوية التي تنشئ ملفاً بصلاحيات root تنتج عادةً ملفاً مملوكاً لك. أما الحاوية التي تنشئ ملفاً بـ UID 1000 فتنتج عادةً ملفاً مملوكاً لمعرّف فرعي، مثل 100999 إذا كان النطاق يبدأ من 100000. يعتمد وصول الـshell الخاص بك على الصلاحيات وقوائم التحكم في الوصول (ACLs)؛ وعادة ما يعتمد الحذف على المجلد الحاوي، لذا يمكنك حذف ذلك الملف من مجلد تتحكم فيه أنت. لذا، فإن قيمة PUID الصحيحة على الـdaemon الذي يعمل بصلاحيات root هي قيمة خاطئة هنا. الآليتان تغيران الملكية في طبقات مختلفة، وتكديسهما دون فحص قد يتركك غير قادر على الكتابة في البيانات المثبتة. إذا انتقلت إلى وضع rootless، اختبر ملكية ملف واحد مكتوب على خادمك قبل ترحيل مكتبة برمجية إليه.

بالنسبة لمعظم حزم الخدمات ذاتية الاستضافة على خادم VPS واحد، فإن استخدام PUID و PGID على daemon يعمل بصلاحيات root هو الخيار العملي، لأنه ما بُنيت الصور ووثقت من أجله. اتجه لاستخدام user: عندما يذكر ملف README الخاص بالصورة أنها مختبرة لهذا الغرض، أو عندما تشغل صورة رسمية من المصدر لا تدعم PUID نهائياً. تقع مساحة عمل المستندات مثل مثيل AFFiNE ذاتي الاستضافة على خادم VPS واحد ضمن هذه الحالة الأخيرة، لأن أياً من حاوياتها لا يقرأ PUID، ويتم تحديد ملكية مجلد قاعدة البيانات والملفات المرفوعة بواسطة بيئة التشغيل بدلاً من أي شيء في كتلة متغيرات البيئة. الأمر نفسه ينطبق على مكتب دعم Chatwoot ذاتي الاستضافة، حيث تكتب حاوية Rails وعامل Sidekiq الخاص بها في مجلد مرفقات واحد ولا يقرأ أي منهما PUID، لذا يجب أن يتطابق ذلك المجلد مع المستخدم الذي تعمل به الصورة بالفعل. لا يتغير أي من ذلك بالنسبة للحزم الأحدث أيضاً، لذا فإن منح كل شخص في الفريق وكيل OneCLI معزول خاص به يترك مجلدات مساحة العمل لكل شخص ومجلد بيانات Postgres مملوكاً للمستخدم الذي تعمل به كل صورة بالفعل، مما يجعلها مشكلة user: و chown بدلاً من كونها مشكلة PUID. عند وضع واجهة برمجة تطبيقات ذاتية الاستضافة أمام Codex و Claude Code و Hermes، تدير نقطة الدخول الخاصة بها هويات متعددة: يجب أن تبدأ الحاوية بصلاحيات root، وتعمل وحدة التحكم والبوابة كمستخدم غير متميز، وتعمل كل جلسة وكيل كمستخدم خاص بها. لا تضف user: إلى ذلك النشر؛ فنقطة الدخول الخاصة بها تتولى إدارة ملكية مجلد البيانات.

حالة حزمة الوسائط: مجموعة واحدة مشتركة عبر الحاويات

تصبح هذه المسألة عملية عند التعامل مع حزمة وسائط arr التي تضم Sonarr وRadarr وعميل تحميل. يكتب عميل التحميل ملفاً مكتملاً في /data/downloads. ثم يقوم Sonarr بإنشاء رابط صلب (hardlink) أو نقل ذلك الملف إلى /data/media. لكي يعمل الرابط الصلب، تحتاج الحاويتان إلى صلاحية الكتابة في نفس المسار. إذا كان عميل التحميل يعمل بمعرّف 1000 بينما يعمل Sonarr بمعرّف 1001 دون صلاحيات كتابة مشتركة للمجموعة، فستمتلك إحدى الحاويتين ملفات لا يمكن للأخرى سوى قراءتها.

الحل هو استخدام مجموعة مشتركة تستخدمها كل حاوية في الحزمة كمعرّف مجموعة (PGID) خاص بها:

sudo groupadd -g 13000 media
sudo usermod -aG media deploy
sudo chown -R deploy:media /srv/media
sudo find /srv/media -type d -exec chmod 2775 {} +
sudo find /srv/media -type f -exec chmod 0664 {} +

الرمز 2 في بداية 2775 هو بت setgid. عند تطبيقه على دليل، يعني ذلك أن كل ملف جديد أو دليل فرعي يتم إنشاؤه بداخله يرث المجموعة media بدلاً من المجموعة الأساسية لمنشئ الملف. وبذلك يستمر هذا الإعداد مع التنزيلات الجديدة دون الحاجة لإعادة تنفيذ chown. سجّل الخروج ثم عُد، أو نفّذ newgrp media قبل التحقق من صلاحياتك؛ فالمجموعة المضافة عبر usermod -aG لا تظهر في جلسة الصدفة (shell) المفتوحة حالياً.

داخل الحاوية، يقوم groupmod -o -g 13000 abc بإعادة ترقيم المجموعة abc إلى 13000، بحيث يكتب abc بنفس معرّف المجموعة (GID) الخاص بمجموعة المضيف media. تحتفظ كل حاوية من linuxserver تصل إلى هذا المسار بمعرّف مستخدم (PUID) خاص بها وتشارك ذلك المعرّف (PGID) الواحد. يشمل ذلك الحاويات التي تليها في السلسلة والتي تقرأ المكتبة النهائية فقط، مثل Jellyfin نفسه. تتصل واجهة أمامية مثل Halcyon، التي تعرض تلك المكتبة كمتجر فيديو من التسعينيات بـ Jellyfin عبر HTTP باستخدام HALCYON_JELLYFIN_URL؛ ولا يحتاج نشرها القياسي إلى معرّف مجموعة الوسائط المشترك ولا إلى ربط دليل الوسائط.

بعد ذلك، اضبط UMASK=002 في كل حاوية linuxserver ضمن الحزمة. هذه هي الخطوة التي يغفل عنها الكثيرون. إذا تُركت دون ضبط، تحتفظ التطبيقات بقناع umask الموروث ما لم يقم شيء آخر بتغييره، والقيمة الافتراضية التي تظهر في ملفات README للصور هي UMASK=022. مع قناع umask فعلي قيمته 022، يحصل التطبيق الذي يطلب 0666 لملف جديد على 0644 في حال عدم وجود ACL افتراضي: يمكن لبقية أعضاء المجموعة قراءته ولكن لا يمكنهم تغييره، مما يبطل معظم إعدادات المشاركة التي قمت بها للتو. مع 002 وبدون ACL افتراضي، يحصل التطبيق الذي يطلب 0666 للملفات و0777 للأدلة على ملفات بصيغة 0664، وداخل الدليل الذي يحمل بت setgid، يحصل على أدلة بصيغة 2775، مما يسمح للمجموعة بالكتابة. يقوم قناع umask بإزالة البتات فقط، لذا فإن التطبيق الذي يطلب 0600 سيحصل دائماً على 0600، كما أن الدليل الذي يحمل ACL افتراضياً يتجاهل umask تماماً. أضف المتغير بجانب PUID وPGID:

services:
  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - UMASK=002
      - TZ=Etc/UTC
    volumes:
      - /srv/appdata/sonarr:/config
      - /srv/media:/data
    restart: unless-stopped

تنتمي هاتان القيمتان إلى ملف .env بجانب ملف Compose، بحيث تقرأ الحزمة بأكملها تعريفاً واحداً:

PUID=1000
PGID=13000

يقرأ Compose هذا الملف تلقائياً لاستبدال المتغيرات بنمط ${PUID}، وهي نفس الآلية التي تستخدمها لبيانات الاعتماد. تنطبق العادات المتعلقة بـ إبقاء القيم خارج ملف docker-compose.yml ووضعها في ملف .env هنا أيضاً، مع اختلاف أن هذين الرقمين ليسا سريين.

تحقق من الإعداد بالكامل بدلاً من الوثوق في التكوين. اكتب ملفاً جديداً بصفتك مستخدم التطبيق، مع تطبيق قناع umask المكوّن، واقرأه من المضيف. استخدم اسم ملف اختبار غير موجود مسبقاً:

docker exec --user abc sonarr sh -c 'umask "$UMASK" && touch /data/downloads/permtest'
ls -ln /srv/media/downloads/permtest

تظهر النتيجة السليمة معرّف PUID الخاص بك كمالك، و13000 كمجموعة، و-rw-rw-r-- كنمط للملف. إذا كانت المجموعة تقرأ 1000، نفّذ ls -ldn /srv/media/downloads: إما أن بت setgid (الرمز s في drwxrwsr-x) مفقود من ذلك الدليل، أو أن الدليل نفسه لا يزال ينتمي للمجموعة 1000 بدلاً من media، وسيقوم أمرا chown وchmod 2775 المذكوران أعلاه بإصلاح كلتا الحالتين. إذا كان النمط يقرأ -rw-r--r--، تحقق من قيمة UMASK في الحاوية وACL الافتراضي للدليل؛ أعد إنشاء الحاوية إذا كانت بيئتها قديمة. يتحقق هذا الاختبار من الإنشاء كـ abc بالقناع المكوّن؛ لا يزال نمط الإنشاء الخاص بالتطبيق وقناع umask الفعلي يحددان ملفاته. احذف ملف الاختبار باستخدام rm /srv/media/downloads/permtest عند الانتهاء.

أي الصور تستخدم أي متغير

تستخدم صور linuxserver.io المتغيرات PUID و PGID و UMASK. بينما يستخدم Paperless-ngx أسماء مختلفة لنفس الغرض وهي USERMAP_UID و USERMAP_GID، وكلاهما يضبط القيمة الافتراضية على 1000، وتوجهك وثائقه لقراءتها من id -u و id -g. وتظهر خوادم الصور نفس التباين: فلدى PhotoPrism زوج المتغيرات الخاص به PHOTOPRISM_UID و PHOTOPRISM_GID، بينما لا توفر Immich أي مكافئ وتترك مستخدم الحاوية لإعداد user: الخاص بـ Docker، لذا فإن الاختيار بين PhotoPrism و Immich يحدد أيضاً أي من هذه الآليات ستتولى صيانتها لأكبر مكتبة على الخادم. تشحن العديد من الصور الرسمية، بما في ذلك صور قواعد البيانات وخوادم الويب الشائعة، مستخدماً مدمجاً ثابتاً وتتوقع منك استخدام user: أو تركه كما هو. تثير عمليات نشر التطبيقات الفردية الصغيرة نفس السؤال، لذا عندما تقوم بإعداد متتبع تمارين openGym ذاتي الاستضافة، يجدر بك التحقق من المستخدم الذي تعمل الحاوية بصلاحياته قبل توجيه bind mount إليه، لأن المجلد الذي يحتوي على قاعدة بياناتها يرث تلك الهوية سواء قمت بضبط PUID أم لا. يندرج ترحيل الوصول عن بعد ضمن نفس الفئة، لذا عندما تشغل خادم ترحيل RustDesk الخاص بك، فإن زوج مفاتيح Ed25519 الذي يكتبه hbbs عند البدء لأول مرة سيصل إلى bind mount الخاص بك مملوكاً للمستخدم الذي انتهت إليه تلك الصورة. يمكنك تصحيح ذلك لاحقاً باستخدام أمر chown على المضيف، أو اختيار الهوية مسبقاً باستخدام مفتاح user:، لأن تلك الصورة لا تضبط مستخدماً خاصاً بها، طالما أن المجلد المثبت قابل للكتابة بواسطة المعرّف (ID) الذي تختاره. ينطبق الشيء نفسه على البنية التحتية التي تضيفها لاحقاً، لذا فإن وضع Authentik أمام تطبيقاتك لتسجيل دخول موحد يعني تشغيل صور Authentik و Postgres الرسمية التي لا تقرأ PUID على الإطلاق، وتأتي ملكية المجلدات (volumes) من المستخدمين الذين تعمل عملياتهم بصلاحياتهم ومن الإعدادات التي تنفذها نقاط الدخول (entrypoints). أزالت Authentik اعتماديتها على Redis في الإصدار 2025.10.

لذا تحقق من ملف README الخاص بكل صورة قبل نسخ كتلة متغيرات البيئة بين المشاريع. يمرر Docker أي متغير بيئة تضبطه إلى أي حاوية، سواء كان هناك شيء بداخلها يقرأه أم لا، والمتغير PUID الذي لا يستهلكه أي شيء لا ينتج خطأً ولا تحذيراً ولا تأثيراً. تبدأ الحاوية كمستخدم محدد بواسطة إعداد user: في Docker أو ملف Dockerfile، ويمكن لنقطة الدخول الخاصة بها بعد ذلك خفض الصلاحيات قبل بدء التطبيق. قم بهذه القراءة قبل إضافة أي شيء جديد إلى الخادم، بما في ذلك حزمة فحص الأمان open-kritt ذاتية الاستضافة، حيث يخبرك ملف Compose ما إذا كانت الصور تحترم PUID أو ما إذا كانت ملكية المجلدات التي تثبتها ثابتة ومحددة بواسطة الصور نفسها.

FAQ

لماذا تظهر ملفات Docker الخاصة بي بملكية 911:911؟

911 هو معرف المستخدم (UID) ومعرف المجموعة (GID) للمستخدم abc المدمج في صور linuxserver.io. رؤية هذا الرقم تعني أنه يطابق القيم الافتراضية المدمجة، لكن الملفات قد تحتفظ بهذه الملكية بعد تغييرك لـ PUID و PGID الخاص بالحاوية. يعرض ls -l الأرقام الخام عندما لا يطابق أي حساب على مضيفك هذه المعرفات، لذا لا يوجد اسم ليتم عرضه. اضبط PUID و PGID على مخرجات id، وأعد إنشاء الحاوية باستخدام docker compose up -d، ثم أصلح الملفات الموجودة باستخدام sudo chown -R 1000:1000 على المجلد المتأثر.

هل تعمل PUID و PGID مع كل صور Docker؟

لا. هي ليست ميزة في Docker ولا يقرؤها Docker أبداً. هي تعمل فقط مع الصور التي تقرأ نقطة دخولها (entrypoint) هذه المتغيرات وتستدعي usermod و groupmod قبل بدء التطبيق، وهذا ينطبق على عائلة linuxserver.io وبعض المشاريع التي نسخت هذا النمط. تستخدم مشاريع أخرى أسماء مختلفة، مثل USERMAP_UID و USERMAP_GID في paperless-ngx. في صورة لا تقرأ أياً منهما، يتم قبول المتغيرات وتجاهلها دون أي تحذير.

هل يجب أن أستخدم PUID و PGID أم مفتاح user: في Docker Compose؟

استخدم PUID و PGID عندما تدعم الصورة ذلك، لأن نقطة الدخول تظل تعمل بصلاحيات root لفترة كافية لإصلاح /config وبدء خدماتها الخاصة بشكل صحيح. استخدم user: عندما توثق الصورة دعمها للمستخدم المختار؛ عدم دعم PUID وحده لا يعني أن نقطة الدخول تعمل بدون root. في صورة linuxserver، يؤدي ضبط user: إلى جعل PUID و PGID غير فعالين، ويوقف تشغيل Docker Mods والخدمات المخصصة، ويجعل أذونات كل وحدة تخزين (volume) مثبتة مسؤوليتك بالكامل.

يمتلك Sonarr معرف PUID الصحيح ولكنه لا يزال غير قادر على نقل الملفات. ما الخطأ؟

تحقق من ثلاثة أمور بالترتيب. أولاً، نقطة تثبيت الوسائط (media mount) نفسها: يقوم نص إعداد المستخدم في الصورة الأساسية بتنفيذ chown على /app و /config و /defaults، لذا يحتفظ /data أو /downloads بأي ملكية لديه على المضيف. ثانياً، المجموعة المشتركة: امنح الحاويات التي تصل إلى شجرة الوسائط نفس PGID وأذونات الكتابة للمجموعة. ثالثاً، القناع (umask): القناع الفعال 022 ينتج ملفات بوضع 0644 عندما يطلب التطبيق 0666 ولا يتم تطبيق أي ACL افتراضي، لذا يمكن للحاويات الأخرى في المجموعة قراءتها ولكن لا يمكنها تعديلها. ترك UMASK غير مضبوط لا يضمن قناعاً أو وضع ملفات معيناً. اضبط UMASK=002 وقم بتعيين بت setgid على المجلدات باستخدام chmod 2775 لكي ترث الملفات الجديدة المجموعة. التطبيق الذي يطلب 0600 لا يزال ينشئ ملفات خاصة، ويغير ACL الافتراضي كيفية تعيين أذونات الإنشاء.

هل كان هذا المقال مفيدًا؟