وبلاگ نت‌آرامآموزش، تجربه و راهکارهای زیرساخت

رفع خطای 200/CHDIR در سرویس لینوکس؛ مسیر کاری را درست کنید

آموزش پیدا کردن WorkingDirectory اشتباه، بررسی مجوز کاربر سرویس و اصلاح امن خطای 200/CHDIR در سرور لینوکسی.

انتشار:
توسط تیم فنی نت‌آرام
۸ دقیقه زمان مطالعه
۰ دیدگاه
محتوای تخصصی، ساده و کاربردی
هماهنگ با هویت حرفه‌ای نت‌آرام
بازگشت به لیست مقالات
تصویر شاخص مقاله رفع خطای 200/CHDIR در سرویس لینوکس؛ مسیر کاری را درست کنید در وبلاگ نت‌آرام
محتوای آموزشی وبلاگ نت‌آرام
سرویسی را روی سرور راه‌اندازی می‌کنید، اما به‌جای شروع برنامه پیام status=200/CHDIR ظاهر می‌شود. این پیام معمولاً یعنی systemd نتوانسته پیش از اجرای برنامه وارد پوشه کاری تعیین‌شده شود. ممکن است پوشه وجود نداشته باشد، کاربر سرویس اجازه عبور از یکی از پوشه‌های مسیر را نداشته باشد یا دیسکی که پوشه روی آن قرار دارد هنوز وصل نشده باشد.
پوشه کاری جایی است که برنامه اجرای خود را از آن شروع می‌کند؛ با مسیر فایل اجرایی یکی نیست. این راهنما را می‌توانید روی لینوکسِ سرور مجازی ایران یا سرور اختصاصی ایران انجام دهید. نام myapp.service و مسیر /srv/myapp/current نمونه هستند. در ترمینال SSH آن‌ها را با نام و مسیر واقعی خود جایگزین کنید و پیش از تغییر سرویس، زمان قطع احتمالی و روش بازگشت را در نظر بگیرید.

۱. مطمئن شوید خطا واقعاً CHDIR است

کد / دستورsystemctl status myapp.service --no-pager
بخش Active و چند خط آخر گزارش را بخوانید. سپس جزئیات بیشتری از همان سرویس بگیرید:
کد / دستورsudo journalctl -u myapp.service -b -n 80 --no-pager
گزینه -b گزارش بوت جاری و -n 80 هشتاد خط آخر را نشان می‌دهد. به خط قبل از 200/CHDIR توجه کنید: No such file or directory معمولاً به نبودن مسیر یا بخشی از آن اشاره دارد؛ Permission denied سرنخ مجوز یا سیاست امنیتی است. نام سرویس، زمان و متن دقیق را یادداشت کنید. اگر خطا 203/EXEC است، مسیر تشخیص فرق می‌کند؛ راهنمای خطای 203/EXEC را بخوانید.
طبق فهرست کدهای systemd، کد ۲۰۰ به مرحله تغییر پوشه کاری مربوط است. تا این مرحله ممکن است برنامه اصلی هنوز اجرا نشده باشد؛ نصب دوباره آن یا دادن دسترسی root به سرویس، بدون شناخت علت، راه‌حل مناسبی نیست.

۲. مسیر و کاربر واقعی را از تنظیم بخوانید

کد / دستورsystemctl cat myapp.service systemctl show myapp.service -p User -p Group -p WorkingDirectory -p RootDirectory -p RootImage
در خروجی به WorkingDirectory و User دقت کنید. مثلاً اگر WorkingDirectory=/srv/myapp/current و User=appuser باشد، systemd باید بتواند در شرایط سرویس با آن کاربر وارد این مسیر شود. اگر User خالی است، معنای آن به نوع واحد و مدیر systemd بستگی دارد؛ برای سرویس سیستمی معمولاً کاربر پیش‌فرض root است. از روی مثال ما کاربر تازه نسازید.
اگر RootDirectory یا RootImage تنظیم شده باشد، مسیر کاری از دید ریشه محدودشده سرویس تفسیر می‌شود و ممکن است با همان مسیر در سیستم میزبان متفاوت باشد. بعضی سرویس‌ها از محدودسازی دسترسی یا mount namespace هم استفاده می‌کنند. بنابراین موفق‌شدن یک دستور در نشست root به‌تنهایی ثابت نمی‌کند سرویس همان مسیر را می‌بیند.

۳. مسیر وجود دارد؟ لینک نمادین سالم است؟

در مثال زیر مسیر واقعی سرویس خودتان را بگذارید:
کد / دستورls -ld /srv/myapp/current namei -l /srv/myapp/current realpath -e /srv/myapp/current
ls اطلاعات خود پوشه را نشان می‌دهد؛ namei هر بخش مسیر و مالک و مجوز آن را جدا می‌کند؛ realpath -e مسیر نهایی را در صورت وجود همه اجزا نشان می‌دهد. اگر current یک لینک به پوشه انتشار دیگری باشد و مقصد آن پاک یا جابه‌جا شده باشد، باید استقرار درست را برگردانید یا لینک را طبق روش انتشار برنامه اصلاح کنید. ساخت یک پوشه خالی به‌جای کد و تنظیمات گمشده، مشکل برنامه را حل نمی‌کند.
اگر پوشه واقعی برنامه مثلاً /srv/myapp/release-2 است اما سرویس هنوز به مسیر قبلی اشاره می‌کند، اول مطمئن شوید همان نسخه سالم و کامل است. سپس مسیر کاری را با یک تنظیم تکمیلی اصلاح کنید:
کد / دستورsudo systemctl edit myapp.service
ویرایشگر باز می‌شود. در بخش قابل ویرایش، مقدار نمونه زیر را با مسیر درست خود وارد و ذخیره کنید:
کد / دستور[Service] WorkingDirectory=/srv/myapp/release-2
این دستور به‌جای دست‌کاری مستقیم فایل اصلی بسته، یک drop-in می‌سازد. پس از ذخیره موفق، systemd تنظیمات را بازخوانی می‌کند؛ با systemctl cat myapp.service مطمئن شوید خط تازه دیده می‌شود. اگر پروژه از مسیرهای نسبی استفاده می‌کند، تغییر پوشه کاری روی محل خواندن فایل‌ها هم اثر دارد. در صورت نیاز با همان روش ویرایش، فقط خطی را که اضافه کرده‌اید برگردانید و به تنظیمات دیگر دست نزنید.

۴. پوشه هست اما دسترسی رد می‌شود

برای ورود به یک پوشه، کاربر سرویس باید اجازه عبور از همه پوشه‌های مسیر را داشته باشد، نه فقط پوشه آخر. خروجی namei -l برای پیدا کردن همان قسمت مفید است. برای مقایسه، در مثال زیر با کاربر واقعی سرویس آزمون انجام می‌دهیم:
کد / دستورsudo -u appuser test -x /srv/myapp/current echo $?
عدد 0 یعنی آن آزمون مجوز عبور را در شرایط این نشست تأیید کرده و عدد غیرصفر یعنی مسیر قابل عبور نبوده یا خطای دیگری رخ داده است. این آزمون محدودیت‌های اضافی systemd، SELinux یا گروه‌های تکمیلی خاص سرویس را کامل شبیه‌سازی نمی‌کند. برای دیدن گروه‌های کاربر و مجوز مسیر نیز می‌توانید اجرا کنید:
کد / دستورid appuser ls -ld /srv /srv/myapp /srv/myapp/current
مثلاً اگر فقط پوشه نهایی متعلق به appuser است و مجوز اجرای مالک آن به اشتباه حذف شده، بعد از ثبت مجوز قبلی، این تغییر محدود می‌تواند عبور مالک از همان پوشه را برگرداند:
کد / دستورsudo chmod u+x /srv/myapp/current
این مثال فقط وقتی مناسب است که مالک واقعاً همان کاربر مورد انتظار باشد و نیاز برنامه را شناخته باشید. اگر مشکل در /srv/myapp یا مسیر دیگری است، همان جزء و روش دسترسی گروهی مجاز را اصلاح کنید. بازکردن همه مسیر با chmod -R 777 یا تغییر مالکیت بازگشتی فایل‌های برنامه می‌تواند داده و امنیت را به خطر بیندازد و برای رفع این خطا لازم نیست.
اگر مسیر داخل /root قرار دارد و سرویس با کاربر عادی اجرا می‌شود، معمولاً آن کاربر نمی‌تواند از /root عبور کند. به‌جای بازکردن خانه root برای همه، برنامه را طبق روش استقرارش به مسیری مناسب برای سرویس منتقل کنید و مسیر جدید را در واحد و تنظیمات مرتبط هماهنگ کنید. پیش از انتقال، فایل‌های داده و مجوزهای لازم را بشناسید و نسخه قابل بازگشت داشته باشید.

۵. اگر مشکل بعد از ریبوت یا روی دیسک جداست

ممکن است پوشه روی دیسک جدا یا یک فضای شبکه باشد که در زمان شروع سرویس آماده نیست. برای دیدن فایل‌سیستم پوشش‌دهنده مسیر نمونه:
کد / دستورfindmnt -T /srv/myapp -o TARGET,SOURCE,FSTYPE,OPTIONS
منبع و نقطه اتصال را با دیسک یا فضای مورد انتظار مقایسه کنید. اگر پوشه روی mount جداست، findmnt -M را برای نقطه اتصال دقیق همان دیسک نیز اجرا کنید. وقتی mount غایب است، ممکن است همان مسیر روی دیسک اصلی دیده شود؛ وجود پوشه به‌تنهایی اتصال منبع درست را ثابت نمی‌کند.
اگر وابستگی سرویس به mount در تنظیم آن ثبت نشده، در برخی استقرارها گزینه زیر در drop-in واحد کمک می‌کند systemd مانت‌های لازم را پیش از شروع سرویس در نظر بگیرد:
کد / دستور[Unit] RequiresMountsFor=/srv/myapp/current
پیش از افزودن، منبع و روش اتصال را با تنظیمات خود تطبیق دهید. این گزینه اصالت دیسک یا درست‌بودن فایل‌های برنامه را تضمین نمی‌کند. اگر منبع اشتباه است، ابتدا مشکل اتصال را رفع کنید. برای نشانه‌های دقیق‌تر، گزارش بوت و وضعیت واحد mount مربوط را بخوانید. اگر مشکل فقط پس از ریبوت رخ می‌دهد، بعد از اصلاح در یک زمان نگهداری، روشن‌شدن سرویس و منبع مانت را مجدداً بررسی کنید.

۶. امنیت سیستم و آزمون نهایی

در AlmaLinux یا سیستم دیگری که SELinux فعال دارد، مجوز عادی فایل ممکن است درست باشد ولی سیاست امنیتی دسترسی را رد کند. وضعیت را ببینید:
کد / دستورgetenforce sudo ausearch -m AVC -ts recent
اگر ابزارها نصب‌اند و گزارش مرتبط با همان سرویس و زمان خطا وجود دارد، برچسب و سیاست مخصوص برنامه را با مستندات توزیع مقایسه کنید. در اوبونتو، محدودیت AppArmor نیز ممکن است دخیل باشد. خاموش‌کردن کامل SELinux یا AppArmor راه تشخیص نهایی نیست؛ علت و سیاست همان سرویس را هدفمند اصلاح کنید.
پس از اصلاح، واحد را از نظر خطاهای قابل تشخیص بررسی کنید:
کد / دستورsudo systemd-analyze verify myapp.service
نبود خروجی به معنی تضمین دسترسی همه مسیرها در زمان اجرا نیست. اگر به دلیل تلاش‌های پی‌درپی محدودیت شروع فعال شده، بعد از رفع علت شمارنده شکست را پاک و سرویس را شروع کنید:
کد / دستورsudo systemctl reset-failed myapp.service sudo systemctl restart myapp.service systemctl status myapp.service --no-pager
راه‌اندازی مجدد ممکن است اتصال کاربران را قطع کند. گزارش تازه journalctl و پاسخ واقعی برنامه را نیز بررسی کنید؛ سبزشدن وضعیت سرویس به‌تنهایی اثبات سالم‌بودن عملکرد آن نیست. اگر اکنون خطای جدیدی مثل 203/EXEC ظاهر شد، مرحله قبلی رفع شده و باید خطای تازه را جداگانه دنبال کنید.
اشتراک‌گذاری:
لینکدینتلگرامایکس
مقاله قبلی
مقاله قبلی وجود ندارد.

دیدگاه‌ها (۰)

دیدگاه‌های تاییدشده و پاسخ‌های تیم نت‌آرام