نحوه برطرف کردن خطای ۵۰۰ Internal Server Error در ویندوز سرور ۲۰۰۸
خطای 500 Internal Server Error یعنی IIS درخواست را پذیرفته و اجرای برنامه را شروع کرده، اما در میانه کار به خطایی برخورده و متن واقعی آن را از دید بازدیدکننده پنهان کرده است. بنابراین کار درست، گشتن دنبال «راه حل خطای 500» نیست؛ کار درست این است که ابتدا پیام پنهانشده را آشکار کنید، یعنی کد فرعی خطا را از لاگ IIS بیرون بکشید و نمایش خطای کامل را بهطور موقت روشن کنید.
کد 500 یک دستهبندی است، نه یک تشخیص
وبسرور این پاسخ را زمانی برمیگرداند که برنامه یا یکی از ماژولهای آن استثنا داده باشد، فایل پیکربندی خوانده نشود، یا Application Pool نتواند برنامه را بالا بیاورد. دهها علت کاملاً متفاوت به همین یک پیام ختم میشوند، بنابراین امتحانکردن راه حلهای پراکنده اینترنتی معمولاً وقت تلفکردن است.
نکته کلیدی که بیشتر مدیران سرور از آن بیخبرند این است: IIS بهصورت پیشفرض متن کامل خطا را فقط به مرورگری نشان میدهد که روی خودِ سرور باز شده باشد. مقدار پیشفرض ویژگی errorMode برابر DetailedLocalOnly است و در ASP.NET هم customErrors بهصورت پیشفرض روی RemoteOnly تنظیم شده است. پس اولین و ارزانترین آزمایش این است که با ریموتدسکتاپ به سرور وصل شوید و همان صفحه را از داخل سرور و با نشانی http://localhost/ باز کنید؛ در بسیاری از موارد متن کامل خطا همانجا ظاهر میشود.
پیش از هر کار: ویندوز سرور ۲۰۰۸ دیگر وصله امنیتی نمیگیرد
پشتیبانی توسعهیافته ویندوز سرور ۲۰۰۸ و ۲۰۰۸ R2 در ۱۴ ژانویه ۲۰۲۰ و ویندوز سرور ۲۰۱۲ و ۲۰۱۲ R2 در ۱۰ اکتبر ۲۰۲۳ به پایان رسیده است. این نسخهها دیگر بهروزرسانی امنیتی عمومی دریافت نمیکنند، بنابراین نگهداشتن یک وبسرور عمومی روی آنها فارغ از هر خطایی یک ریسک است. نسخههایی که امروز پشتیبانی میشوند ویندوز سرور ۲۰۱۶، ۲۰۱۹، ۲۰۲۲ و ۲۰۲۵ هستند و مسیر درست، مهاجرت به یکی از اینهاست، نه ادامهدادن روی نسخه از رده خارج.
خبر خوب این است که روش عیبیابی که در ادامه میآید از IIS نسخه ۷ به بعد تا امروز تقریباً بدون تغییر مانده و روی نسخههای جدید هم دقیقاً به همین شکل کار میکند. اگر روی هاست ویندوز ایران هستید، بخشهای مربوط به لاگ و تنظیمات سطح سرور را باید از پشتیبانی بخواهید، چون در محیط اشتراکی دسترسی مستقیم به آنها ندارید.
گام یک: کد فرعی خطا را از لاگ IIS بخوانید
مهمترین اطلاعات در همان لاگ استاندارد IIS نوشته میشود و برای دیدنش لازم نیست چیزی را تغییر دهید. لاگها بهصورت پیشفرض در این مسیر قرار دارند:
- مسیر لاگ:
%SystemDrive%inetpublogsLogFiles - پوشه هر سایت با شناسه آن نامگذاری میشود، مثل
W3SVC1 - لاگ رویدادهای ویندوز: Event Viewer ←
Windows Logs←Application
در هر خط لاگ دنبال سه ستون بگردید: sc-status که همان 500 است، sc-substatus که کد فرعی و در عمل تشخیص واقعی شماست، و sc-win32-status که کد خطای ویندوز را میدهد. ترکیب 500 و 19 یعنی خطای 500.19؛ همین یک عدد مسیر عیبیابی را از حدسزدن به یک مشکل مشخص تبدیل میکند.
گام دو: نمایش خطای کامل را موقتاً روشن کنید
اگر لاگ کافی نبود، فایل web.config سایت را در ریشه آن باز کنید و تنظیمات زیر را اضافه کنید. توجه کنید که این خطوط باید داخل بخش مربوطه قرار بگیرند، نه پیش از آن؛ اشتباه رایجی که خودش باعث خطای دیگری میشود:
- داخل
<system.webServer>بنویسید:<httpErrors errorMode="Detailed" /> - برای ASP.NET، داخل
<system.web>بنویسید:<customErrors mode="Off" /> - برای برنامههای Classic ASP، داخل
<system.webServer>بنویسید:<asp scriptErrorSentToBrowser="true" />
فایل را ذخیره کنید و صفحه را دوباره بارگذاری نمایید. اگر درست همینجا خطای 500.19 گرفتید، یعنی آن بخش پیکربندی در سطح سرور قفل شده و اجازه بازنویسی در سطح سایت را ندارد. در این حالت روی خود سرور و با دسترسی مدیر، قفل را باز کنید:
%windir%system32inetsrvappcmd.exe unlock config /section:system.webServer/httpErrors
اگر ویرایش دستی web.config و کار با خط فرمان را ترجیح نمیدهید، کنترلپنل پلسک روی ویندوز سرور هم نصب میشود و بخش زیادی از همین تنظیمات را به یک رابط تحت وب منتقل میکند.
کدهای فرعی رایج و معنای عملی آنها
| کد | معنا | اولین جایی که باید نگاه کنید |
|---|---|---|
500.0 |
خطای یک ماژول یا ISAPI | کد برنامه و ماژولهای نصبشده روی سایت |
500.19 |
پیکربندی نامعتبر یا غیرقابل خواندن | درستی نحو web.config و دسترسی خواندن روی آن |
500.21 |
ماژول شناخته نشد | قابلیتی که در web.config ارجاع شده ولی روی IIS نصب نیست |
500.100 |
خطای داخلی Classic ASP | خط دقیقی که با scriptErrorSentToBrowser نمایش داده میشود |
500.30 |
شکست راهاندازی برنامه ASP.NET Core | لاگ stdout برنامه |
500.31 |
نسخه مورد نیاز داتنت روی سرور نیست | خروجی dotnet --list-runtimes |
پرتکرارترین علت: دسترسی فایل و هویت Application Pool
بخش پایانی نوشتههای قدیمی درباره این خطا معمولاً میگوید دسترسی خواندن را به کاربر Network Service بدهید. این توصیه امروز نادرست است. از IIS نسخه ۷.۵ به بعد هویت پیشفرض هر Application Pool روی ApplicationPoolIdentity تنظیم شده، یعنی یک حساب مجازی مخصوص همان Pool. اگر دسترسی را به Network Service بدهید، در بیشتر سرورهای امروزی هیچ اتفاقی نمیافتد و مشکل سر جایش میماند.
دسترسی را باید به حساب مجازی همان Pool بدهید. اگر نام Pool شما MySite است، دستور زیر را در Command Prompt با دسترسی مدیر اجرا کنید:
icacls "C:inetpubwwwrootmysite" /grant "IIS AppPoolMySite":(OI)(CI)(RX) /T
گروه IIS_IUSRS و کاربر IUSR هم در برخی پیکربندیها لازم میشوند. برای مسیرهایی که برنامه باید در آنها بنویسد، مثل پوشه بارگذاری فایل یا لاگ، بهجای RX از M استفاده کنید و این دسترسی را فقط به همان پوشه بدهید، نه به کل ریشه سایت. روی سرور مجازی ابری ایران که دسترسی کامل مدیریتی دارید، اجرای این دستورها بدون محدودیت ممکن است.
اگر برنامه ASP.NET Core است
در ASP.NET Core خودِ برنامه یک پروسه جداست و IIS فقط درخواست را به آن میسپارد، بنابراین متن خطا در جای دیگری نوشته میشود. برای دیدنش در web.config، در عنصر <aspNetCore> مقدار stdoutLogEnabled را برابر true بگذارید و stdoutLogFile را به مسیری مثل .logsstdout اشاره دهید؛ پوشه logs باید از قبل ساخته شده و قابل نوشتن باشد. بلافاصله پس از گرفتن پیام خطا این لاگ را دوباره خاموش کنید، چون بدون محدودیت رشد میکند.
هرگز متغیر ASPNETCORE_ENVIRONMENT را روی سرور عمومی برابر Development قرار ندهید؛ این کار صفحه خطای توسعهدهنده را با جزئیات کد و مسیرهای داخلی به همه بازدیدکنندگان نشان میدهد. مقدار درست برای یک سرور عملیاتی Production است و متن خطا را باید از لاگ خواند، نه از مرورگر.
وقتی هیچکدام جواب نداد: Failed Request Tracing
برای خطاهایی که فقط گاهی رخ میدهند یا هیچ ردی در لاگ نمیگذارند، ابزار Failed Request Tracing دقیقترین گزینه است. این قابلیت از IIS نسخه ۷ به بعد وجود دارد اما بهصورت پیشفرض نصب نیست و باید از Server Manager به فهرست نقشهای وبسرور اضافه شود. پس از فعالسازی، یک قانون برای وضعیت 500 تعریف میکنید و IIS برای هر درخواست ناموفق یک فایل XML کامل میسازد که نشان میدهد درخواست دقیقاً در کدام ماژول و در کدام مرحله شکست خورده است.
کار آخر: جزئیات را دوباره ببندید
پس از رفع مشکل، حتماً errorMode را به DetailedLocalOnly و customErrors را به RemoteOnly یا On برگردانید و stdoutLogEnabled را خاموش کنید. صفحه خطای کامل، نسخه داتنت، مسیر فیزیکی فایلها و گاهی رشته اتصال پایگاه داده را در اختیار هر بازدیدکنندهای میگذارد و همین یک فراموشی میتواند از خود خطای اولیه پرهزینهتر تمام شود. اگر ترجیح میدهید اینگونه عیبیابیها را خودتان بر عهده نگیرید، در سرور مجازی مدیریتشده نصب و پیکربندی کنترلپنل و عیبیابی نرمافزارهای نصبشده توسط تیم آنلاین سرور انجام میشود.
خلاصه مسیر درست این است: کد فرعی را از لاگ بخوانید، متن کامل خطا را موقتاً آشکار کنید، علت را بر اساس همان کد فرعی برطرف نمایید و در پایان همهچیز را به حالت امن برگردانید.