SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-21

لماذا يرفض nano الحفظ برسالة Permission denied؟

تظهر رسالة Permission denied في nano لأربعة أسباب شائعة. افحص مالك الملف والدليل الأب، ثم نظام ملفات للقراءة فقط أو ممتلئاً، وأخيراً uid داخل الحاوية.

لماذا لا يحفظ nano ملفك

لن يحفظ nano ملفك لواحد من أربعة أسباب: لا تملك الملف، أو أن الدليل الأب لا يسمح بالعملية التي يحاول nano تنفيذها، أو أن نظام الملفات للقراءة فقط أو لا تتوفر فيه مساحة، أو أنك داخل حاوية تعمل بمعرّف مستخدم مختلف. السببان الأولان متعلقان بالصلاحيات، أما السببان الآخران فلا يتعلقان بها. تحقّق من هذه الأسباب بهذا الترتيب، لأن السبب الأول يغطي معظم الحالات، ولأن تأكيده يتطلب أمراً واحداً، ولأن إصلاحه هو sudoedit وليس sudo nano.

لا يضيع شيء ما دام المحرر مفتوحاً. يبقى النص في الذاكرة، لذلك يمكنك إبقاء الملف مفتوحاً، وكتابة محتويات الذاكرة إلى مسار تملكه، ثم وضعه في مكانه بعد ذلك. يرد هذا الحل البديل قرب نهاية هذا الدليل.

أجرِ هذه الفحوص قبل تغيير أي أذونات

وجّه كل أمر إلى المسار الفعلي الذي تعدّله. تجيب هذه الأوامر عن أسئلة مختلفة، لذلك شغّلها كلها قبل أن تغيّر أي شيء. يؤدي تغيير الأذونات قبل معرفة الفحص الذي يفشل عادةً إلى إنشاء مشكلة ثانية فوق المشكلة الأولى.

id
ls -l /etc/nginx/nginx.conf
ls -ld /etc/nginx
namei -l /etc/nginx/nginx.conf
findmnt -no SOURCE,FSTYPE,OPTIONS -T /etc/nginx/nginx.conf
df -h /etc/nginx
df -i /etc/nginx

يعرض id معرّف المستخدم ومعرّفات المجموعات التي تملكها حالياً. ويعرض ls -l المالك والمجموعة وبتات أذونات الملف نفسه. أما ls -ld فيعرض المعلومات نفسها للدليل الذي يحتوي الملف، وهذا سؤال منفصل وله إجابة منفصلة. ويفحص namei -l كل جزء من المسار، ثم يسرد مالك كل جزء وأذوناته؛ لذلك يجيب عن السؤالين في مخرجات واحدة. ويحدّد findmnt نظام الملفات الموجود تحت ذلك المسار وخيارات تركيبه. ويعرض df -h المساحة المتاحة، بينما يعرض df -i عدد inodes المتاحة، إذ قد تنفد هذه الأخيرة بشكل منفصل عن المساحة. إذا لم تكن سلاسل الأذونات هذه مألوفة لك بعد، فابدأ بقراءة كيفية قراءة سلسلة الأذونات التي يطبعها ls -l.

السبب 1: الملف مملوك للحساب root وأنت لست كذلك

أذونات القراءة والكتابة منفصلة، ومعظم الملفات ضمن /etc قابلة للقراءة من الجميع. لذلك يفتح nano الملف، ويعرض محتواه، ويسمح لك بالكتابة بحرية؛ فلا شيء من ذلك يغيّر محتوى القرص. يحدث الرفض عند الحفظ، عندما تقارن النواة معرّف المستخدم ومعرّفات مجموعاته بالمالك والمجموعة وبِتّات المستخدمين الآخرين في الملف. ينقل nano ما أخبرته به النواة، لذلك لا يغيّر أي خيار في nano النتيجة.

يحسم id وls -l الأمر معاً. الملف مملوك للحساب root، وأنت لست root، كما أن بِتّات المستخدمين الآخرين لا تمنح إذن الكتابة. لن يفيد الضغط على Ctrl-O مرة أخرى.

لماذا يُعد sudoedit الطريقة الصحيحة لتحرير ملف مملوك للحساب root

SUDO_EDITOR=nano sudoedit /etc/nginx/nginx.conf

ينشئ sudo نسخة مؤقتة من الملف، ويضبط مالكها ليكون حسابك، ثم يشغّل nano على تلك النسخة بحسابك العادي، وبعد خروج المحرر ينسخ النتيجة إلى مكانها باستخدام امتيازات root. لا يعمل المحرر بحساب root. الأمر sudo -e هو الأمر نفسه باسم مختلف. يُختار المحرر من SUDO_EDITOR، ثم VISUAL، ثم EDITOR، لذلك يؤدي ضبط export EDITOR=nano في ملف تعريف shell إلى جعل هذا المحرر الافتراضي في كل مكان. إذا كان إعداد env_editor معطلاً في sudoers، فتُتجاهل هذه المتغيرات ويُستخدم المحرر المحدد في إعداد editor داخل sudoers.

يحفظ sudo nano الملف أيضاً، وهذه هي المشكلة. فهو يمنح محرراً تفاعلياً كاملاً امتيازات root على نظام الملفات بأكمله طوال مدة الجلسة. لذلك قد تؤدي كتابة مسار خاطئ في مطالبة الحفظ إلى الكتابة فوق ملف نظام مختلف بصلاحيات root. من المفيد ترسيخ عادة العمل بحساب مستخدم عادي لا يستدعي sudo إلا للخطوات التي تحتاج إليه، ويمثل sudoedit هذه العادة عند تحرير ملف إعدادات.

تتسبب قاعدتا sudoedit التاليتان في مفاجأة بعض المستخدمين. فهو يرفض تحرير رابط رمزي، ويرفض تحرير ملف داخل دليل يمكنك الكتابة إليه، إلا إذا كنت تستخدم حساب root. توجد القاعدة الثانية لأن أي شخص يستطيع الكتابة إلى الدليل يمكنه استبدال الملف أثناء فتحه في المحرر. هذان السلوكان هما الإعدادان الافتراضيان في sudoers (sudoedit_follow معطل، وsudoedit_checkdir مفعّل). إذا لم يكن الملف موجوداً بعد، فسيُنشئه sudoedit لك.

السبب 2: ما الذي يتحكم فيه الدليل الأب فعلياً

تشير إرشادات مكتوبة لمحررين آخرين إلى أن الحفظ يحتاج إلى صلاحية الكتابة على الدليل، لأن كثيراً من المحررات تحفظ بكتابة ملف جديد ثم إعادة تسميته فوق الملف القديم. لا يعمل nano بهذه الطريقة. فهو يفتح الملف الذي حددته ويكتب داخله، لذلك لا يتم الرجوع إلى بت الكتابة الخاص بالدليل أبداً عندما يكون الملف موجوداً مسبقاً.

ما يزال الدليل يتحكم في أمور أخرى، ولهذا السبب توجد ls -ld في قائمة التحقق:

  • يتطلب إنشاء ملف غير موجود بعد صلاحية الكتابة والتنفيذ على الدليل، لأن اسماً جديداً يجب أن يُضاف إليه. تحدد umask الصلاحيات التي يبدأ بها هذا الملف الجديد.
  • يتطلب الوصول إلى الملف أصلاً صلاحية التنفيذ، وتسمى أيضاً صلاحية البحث، على كل دليل في المسار. ويؤدي غيابها عن أي دليل إلى حظر كل ما تحته، وتوضح لك namei -l أي دليل يسبب ذلك.
  • تؤدي عملية الحفظ مع تفعيل النسخ الاحتياطية أو قفل الملفات إلى كتابة ملف ثانٍ بجوار الملف الأصلي، لذلك تحتاج هذه الميزات إلى دليل قابل للكتابة. النسخ الاحتياطية هي الخيار -B أو set backup في nanorc، وقفل الملفات هو -G أو set locking. وكلاهما معطل ما لم تفعّله أنت أو توزيعتك.

تتمتع صلاحيات الدليل بالأهمية نفسها في مواضع أخرى من النظام. يرفض خادم SSH مفتاحاً عندما يكون الدليل المنزلي أو دليل .ssh قابلاً للكتابة من مستخدمين آخرين، وهذا سبب شائع لـرفض SSH لمفتاحك عند تسجيل الدخول.

بما أن nano يكتب داخل الملف الموجود مسبقاً، يحتفظ الملف بـinode الخاص به، وهو الهوية الموجودة على القرص والمقترنة بالاسم. ويستمر أي شيء يحتفظ بالملف مفتوحاً في تتبعه، كما يظل ربط ملف واحد عبر bind mount داخل حاوية عاملاً. أما المحررات التي تحفظ باستبدال الملف فتقطع هذا الربط، لأن الـmount يتبع inode وليس الاسم.

Cause 3: the filesystem is read only, or it has nothing left

findmnt reporting ro in the options means the write was never going to succeed. Either the filesystem was mounted that way, through /etc/fstab or a read only bind mount, or the kernel remounted it read only after a disk error. The second case is the serious one. sudo dmesg -T | tail -50 shows the input/output and filesystem errors that led to the remount, and the repair is a filesystem check while it is unmounted, which on a VPS means booting the provider's rescue console.

A full filesystem fails the same write for a different reason. df -h covers the ordinary case. df -i covers the case people miss: inodes come from a fixed pool created when the filesystem was made, and a tree of tiny files can use them all while df -h still shows free gigabytes. When space is gone and nothing obvious is holding it, df and du disagreeing about a full disk covers the deleted-but-still-open file that causes it.

One detail explains a confusing symptom here. ext4 reserves a share of its blocks for root when the filesystem is created, so root keeps writing after ordinary users are refused. sudo then looks like the fix, the disk fills the rest of the way, and the problem returns in a worse form.

Because nano truncates the file before writing the new contents, a write that runs out of space partway can leave the file shorter than it was. Copy a config you care about before editing it on a filesystem that is nearly full. sudo cp -a /etc/nginx/nginx.conf /root/nginx.conf.bak keeps the owner, group and permissions on the copy.

السبب 4: أنت داخل حاوية وتعدّل نقطة ربط

تُخزَّن ملكية الملفات رقمياً. تخزّن النواة معرّف المستخدم، بينما يأتي الاسم الذي تراه من الجهة التي تنفّذ عملية البحث، وهي /etc/passwd. لذلك قد يظهر الملف باسم على المضيف، وباسم مختلف أو برقم مجرد داخل الحاوية. قارن الأرقام بدلاً من الأسماء: شغّل id -u داخل الحاوية، وشغّل ls -ln على الملف.

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

هناك حالتان إضافيتان في الحاويات تستحقان المعرفة. يرفض mount المُنشأ للقراءة فقط باستخدام :ro الكتابة، كما يرفضها أيضاً تشغيل الحاوية باستخدام --read-only، بغض النظر عما تقوله الملكية. يعرض cat /proc/mounts داخل الحاوية هذا العلم. في Rootless Podman، تربط مساحة أسماء المستخدمين معرّفات المستخدمين داخل الحاوية بنطاق من معرّفات المستخدمين على المضيف. لذلك، قد يبدو الملف مملوكاً لـroot داخل الحاوية، بينما يكون مملوكاً لحسابك غير المميّز خارجها.

توجد أيضاً حالة ينجح فيها التعديل ثم يختفي. إذا غيّرت ملفاً داخل الحاوية، في مسار ليس mount، فإنه يعيش في طبقة الكتابة الخاصة بالحاوية. تُحذف هذه الطبقة عند إعادة إنشاء الحاوية. غيّر الملف في جانب المضيف من mount، أو أثناء بناء image، إذا أردت أن يبقى التغيير.

المخرج الآمن: احفظ الملف في مسار تملكه

لا تحاول الحصول على الصلاحيات من داخل المحرر. اضغط Ctrl-O، وامسح المسار في المطالبة، واكتب مساراً ضمن الدليل الرئيسي الخاص بك، مثل /home/you/nginx.conf.new، ثم اضغط Enter. بعد ذلك اضغط Ctrl-X للخروج. أصبح عملك الآن محفوظاً على القرص ومملوكاً لك، وما تبقى هو نسخ ملف عادي.

sudo cp /home/you/nginx.conf.new /etc/nginx/nginx.conf
sudo nginx -t

استخدم cp هنا بدلاً من mv. يكتب cp عبر الملف الموجود مسبقاً، لذلك يحتفظ ذلك الملف بمالكه ومجموعته وصلاحياته. أما mv في نظام الملفات نفسه، فيستبدله بملفك، ما يترك ملف إعداد في /etc مملوكاً لحساب المستخدم الخاص بك. وتصبح هذه مشكلة الصلاحيات التالية التي يجب عليك حلها.

تحقق من النتيجة باستخدام الأداة التي تدير الملف قبل إعادة تحميل أي شيء. يحلل sudo nginx -t إعدادات nginx، بينما يحلل sudo sshd -t إعدادات خادم SSH. يوجد ملفان لهما محرران مخصصان ينفذان هذا الإجراء كاملاً نيابةً عنك: sudo visudo من أجل /etc/sudoers، وcrontab -e لمهام cron الخاصة بك. يحرر كل منهما نسخة مؤقتة، ويتحقق من الصياغة، ولا يثبت الملف إلا إذا اجتاز التحليل.

FAQ

هل أستخدم sudo nano أم sudoedit لتحرير ملف نظام؟

استخدم sudoedit. ينسخ الملف إلى نسخة مؤقتة يملكها المستخدم الخاص بك، ويشغّل المحرر باسم المستخدم الخاص بك، ثم يكتب النتيجة مجدداً بصلاحيات root عند خروج المحرر. لذلك لا يمتلك المحرر نفسه صلاحيات root مطلقاً. اضبط SUDO_EDITOR أو VISUAL أو EDITOR على nano لاختيار nano. يعمل sudo nano أيضاً، لكنه يمنح المحرر التفاعلي صلاحية root للوصول إلى كل مسار في النظام طوال مدة الجلسة. وهذا يحوّل كتابة اسم ملف بشكل خاطئ عند مطالبتك بالحفظ إلى ملف نظام تالف.

هل أحتاج إلى صلاحية الكتابة على الدليل لحفظ ملف باستخدام nano؟

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

يبدو المالك صحيحاً والقرص غير ممتلئ. ما الذي يمكن أن يمنع الكتابة أيضاً؟

هناك أربعة أسباب. قد يكون نظام الملفات موصولاً للقراءة فقط، ويعرض findmnt -no OPTIONS -T /etc/nginx/nginx.conf ذلك. قد يحمل الملف السمة immutable، ويعرض lsattr هذه السمة ويزيلها sudo chattr -i، ولا يستطيع حتى root الكتابة إلى الملف أثناء تعيينها. قد تكون مجموعة inode مستنفدة مع بقاء مساحة حرة، ويعرض df -i ذلك. وقد يمنع SELinux أو AppArmor الكتابة رغم سماح بتات الصلاحيات بها، ويسجل audit log الرفض مقابل المسار الذي حاولت الكتابة إليه.

أين أضع التغييرات عندما يتعذر حفظ الملف تماماً؟

اضغط Ctrl-O وأدخل مساراً تملكه، ضمن الدليل الرئيسي الخاص بك أو في أي مكان يملك المستخدم الخاص بك صلاحية الكتابة فيه. لا يزال المحتوى المؤقت في الذاكرة، لذلك لن تفقد ما كتبته. انسخ الملف المحفوظ إلى مكانه بعد ذلك باستخدام sudo cp، الذي يحافظ على مالك الملف الأصلي وصلاحياته، ثم افحصه باستخدام أمر الاختبار الخاص بالخدمة قبل إعادة تحميلها.

لماذا تختفي تعديلاتي داخل حاوية Docker؟

عندما لا يكون المسار mount، يُحفظ التعديل في طبقة الكتابة الخاصة بتلك الحاوية، وتُحذف هذه الطبقة عند استبدال الحاوية. حرّر الملف في جانب المضيف من bind mount أو volume، أو أنشئه ضمن image. عندما يكون المسار bind mount ويُرفض الحفظ بدلاً من ذلك، قارن id -u داخل الحاوية بالمالك الرقمي من ls -ln: يحتفظ الملف بملكيته على المضيف، ويجب أن يطابقها المستخدم الذي تعمل به عملية الحاوية.