عیب‌یابی

رفع خطای 503 Service Unavailable — از سقف منابع هاست تا استخر PHP-FPM

رفع خطای 503 Service Unavailable: لایه‌های مسیر درخواست از لبه و وب‌سرور تا استخر PHP-FPM و سقف منابع اکانت، برای تشخیص اینکه کدام لایه پاسخ 503 را ساخته است

رفع خطای 503 وقتی چند دقیقه طول می‌کشد که پیش از دست‌زدن به هر تنظیمی بدانید کدام لایه این پاسخ را ساخته است — و وقتی چند روز طول می‌کشد که کورکورانه عددها را بالا ببرید. برخلاف 500 و 502، در 503 چیزی نشکسته؛ سرویس زنده است و عمداً جواب نمی‌دهد: یا به سقف منابع خورده، یا نرخ درخواست را محدود کرده، یا در حالت تعمیر است. اینجا از روی هدرهای پاسخ و لاگ‌ها مقصر را پیدا می‌کنیم — هاست اشتراکی، استخر PHP-FPM، وب‌سرور، لبه یا اپلیکیشن — و در پایان به بخشی می‌رسیم که هیچ راهنمای فارسی دیگری ندارد: 503 تنها کدی است که برای توقف برنامه‌ریزی‌شده درست است، به شرط کوتاه‌بودن و همراهی هدر Retry-After.

خطای 503 دقیقاً یعنی چه و چه فرقی با 500 و 502 دارد؟

خطای 503 Service Unavailable پاسخی است که سرور می‌فرستد تا بگوید در این لحظه توان یا اجازه‌ی پاسخ‌دادن ندارد، اما وضعیت موقتی است. متن استاندارد RFC 9110 همین را می‌گوید: کد 503 نشان می‌دهد سرور «به دلیل بار موقت یا تعمیرات برنامه‌ریزی‌شده» فعلاً نمی‌تواند درخواست را رسیدگی کند، و اجازه می‌دهد هدر Retry-After را هم بفرستد تا بگوید چقدر باید صبر کرد.

تفاوت با دو خطای همسایه از همین‌جا روشن می‌شود. در 500 کد اپلیکیشن اجرا می‌شود و وسط کار شکست می‌خورد — یعنی چیزی واقعاً خراب است. در 502 پراکسی پاسخ سالمی از بک‌اند نمی‌گیرد یا اصلاً بک‌اندی پیدا نمی‌کند. در 503 هیچ کدی نشکسته؛ اصلاً نوبت به اجرای آن نرسیده است. پس 500 را با خواندن لاگ درمان می‌کنید، 502 را با زنده‌کردن بک‌اند، و 503 را با پیداکردن سقفی که به آن خورده‌اید. دو مورد اول را جداگانه نوشته‌ایم: رفع خطای 500 و رفع خطای 502.

یک نکته‌ی فنی که تقریباً همیشه جا می‌افتد و نیمی از حدس‌های اشتباه را حذف می‌کند: روی پشته‌ی Nginx به‌علاوه‌ی PHP-FPM، اگر بک‌اند بمیرد یا سوکتش پاسخ ندهد، Nginx در لاگ خطا چیزی شبیه connect() to unix:/run/php/php8.4-fpm.sock failed (2: No such file or directory) while connecting to upstream می‌نویسد و به کاربر 502 می‌دهد، نه 503. (پیام no live upstreams که خیلی راهنماها به این حالت نسبت می‌دهند فقط با یک بلوک upstream چندسروره دیده می‌شود — آن هم باز 502 است.) پس روی Nginx مقصر 503 تقریباً هرگز «خاموش‌بودن PHP» نیست؛ یا Nginx نرخ درخواست را محدود کرده، یا کسی return 503 در کانفیگ گذاشته، یا پاسخ از اپلیکیشن آمده. و یک صداقت لازم از دل استاندارد: RFC 9110 تذکر می‌دهد سرور موظف نیست هنگام اشباع از 503 استفاده کند — «بعضی سرورها ممکن است فقط اتصال را رد کنند».

اولین کار: کدام لایه خطای 503 را تولید کرده است؟

هر درخواست از چند لایه عبور می‌کند و هرکدام می‌توانند 503 بسازند: لبه یا CDN، وب‌سرور مبدأ، محدودکننده‌ی منابع هاست اشتراکی، استخر پردازش PHP، و خود اپلیکیشن. دو دستور ساده مرزها را روشن می‌کند. اول هدرهای کامل پاسخ:

curl -sS -o /dev/null -D - https://example.com/

HTTP/2 503
server: LiteSpeed
retry-after: 600
content-type: text/html; charset=UTF-8
cache-control: no-cache, must-revalidate, max-age=0

دو فیلد این خروجی سرنخ می‌دهند. هدر server می‌گوید چه نرم‌افزاری پاسخ را نوشته — اگر نام یک شبکه‌ی لبه آنجا بنشیند و هیچ هدری از مبدأ همراهش نباشد، 503 روی لبه ساخته شده و اصلاً به سرور شما نرسیده است. وجود retry-after یعنی چیزی آگاهانه این پاسخ را فرستاده، نه اینکه سرور از فشار زمین خورده باشد؛ و مقدار دقیق 600 امضای حالت تعمیر وردپرس است. قدم دوم، مقایسه‌ی فایل ایستا با صفحه‌ی دینامیک:

for u in / /wp-content/uploads/logo.png /wp-login.php; do
  printf '%-32s -> ' "$u"
  curl -s -o /dev/null -w '%{http_code}\n' "https://example.com$u"
done

/                                -> 503
/wp-content/uploads/logo.png     -> 200
/wp-login.php                    -> 503

تفسیرش مستقیم است: فایل ایستای 200 کنار صفحه‌ی PHP با 503 یعنی وب‌سرور سالم است و مشکل در لایه‌ی اجرای PHP یا سقف منابع اکانت است. اگر همه چیز — حتی تصویر — 503 بدهد، پاسخ از لایه‌ای بالاتر می‌آید. و اگر فقط یک مسیر خاص 503 بدهد، تقریباً همیشه پای محدودیت نرخ یا یک قانون امنیتی در میان است.

درخت تصمیم تشخیص خطای 503: از هدر server و مقایسه‌ی فایل ایستا با صفحه‌ی دینامیک، به یکی از پنج مقصر — لبه، وب‌سرور، سقف منابع اکانت، استخر PHP-FPM یا اپلیکیشن
پنج لایه‌ای که می‌توانند خطای 503 بسازند و ترتیب کنارزدنشان.
💡 قاعده‌ی تشخیص 503: پیش از تغییر هر عددی سه چیز را یادداشت کنید — هدر server، اینکه فایل ایستا هم 503 می‌گیرد یا نه، و اینکه خطا دائمی است یا فقط در ساعت اوج. همین سه جواب معمولاً لایه‌ی مقصر را قطعی می‌کند.

خطای 503 در هاست اشتراکی: سقف منابع اکانت، رایج‌ترین علت

رایج‌ترین سازنده‌ی خطای 503 روی هاست اشتراکی، خوردن به سقف منابع اکانت است. رایج‌ترین لایه‌ی جداسازی روی سرورهای cPanel و DirectAdmin، CloudLinux با فناوری LVE است؛ اگر سروری CloudLinux نداشته باشد، سقف‌ها معمولاً در استخر PHP-FPM اختصاصی هر کاربر تعریف شده‌اند. از سقف‌هایی که مستندات محدودیت‌های CloudLinux تعریف می‌کند، این‌ها به 503 مربوط‌اند: SPEED برای پردازنده، PMEM برای حافظه‌ی فیزیکی، IO و IOPS برای دیسک، NPROC برای مجموع پروسه‌ها، و EP یا Entry Processes برای درخواست‌های هم‌زمانِ در حال اجرا. سقف VMEM هم هست و همان مستندات رسیدن به آن را عامل «خطای 500 و 503» می‌داند، اما توصیه‌ی صریح CloudLinux صفرگذاشتن VMEM است، چون منسوخ شده.

و اینجا تصحیحی لازم است که تقریباً همه‌ی مطالب فارسی آن را قاطی می‌کنند: وقتی سقف EP پر شود پاسخ 508 است نه 503. آنچه 500 یا 503 می‌سازد رسیدن به سقف NPROC یا PMEM است. پس «Resource Limit Is Reached» با کد 508 یعنی EP؛ 503 یعنی حافظه و تعداد پروسه.

سنجه‌ی درست شمارش بازدید نیست، شمارش هم‌زمانی است: ده هزار بازدید روزانه با صفحه‌های ۲۰۰ میلی‌ثانیه‌ای به‌ندرت به سقف می‌خورد، اما هزار بازدید با صفحه‌های سه‌ثانیه‌ای در پیک به‌راحتی می‌خورد. روی LiteSpeed سقف جداگانه‌ای به نام PHP suEXEC Max Conn هست که به‌ازای هر worker اعمال می‌شود، نه به‌ازای اکانت: با دو worker و مقدار ۱۰، تا حدود ۲۰ پروسه‌ی LSPHP (به‌علاوه‌ی برستی نزدیک ۳۳ درصد) خواهید داشت. پیام لاگش به بالابردن LSAPI_CHILDREN اشاره می‌کند، اما در حالت suEXEC چیزی که باید عوض شود همین PHP suEXEC Max Conn است. مستندات عیب‌یابی 503 در LiteSpeed هم تمام‌شدن حافظه، شکست fork() و پرشدن دیسک را به همین 503 ختم می‌کند.

⚠️ روی هاست اشتراکی این سقف‌ها دست شما نیست. دو کار از شما برمی‌آید: کاهش مصرف — کش صفحه، حذف افزونه‌های سنگین، کوتاه‌کردن زمان اجرای هر درخواست — و ثبت تیکت با ذکر ساعت دقیق خطاها تا پشتیبانی شمارنده‌های تخلف اکانت را در همان بازه ببیند. انتظار درست هم از پنل داشته باشید: نمای سرویس مصرف دیسک و پهنای باند را می‌دهد، اما شمارنده‌های حافظه، پروسه و Entry Process روی خود سرور ثبت می‌شوند و راه رسیدن به آن‌ها تیکت است.

استخر PHP-FPM پر شده است — max_children را چطور حساب کنم؟

روی سرور مجازی یا اختصاصی، اشباع استخر PHP-FPM شایع‌ترین ریشه‌ی خطاهای 5xx است — اما کدی که کاربر می‌بیند به وب‌سرور جلویی بستگی دارد و همین‌جا بیشتر راهنماها اشتباه می‌کنند. مستندات پیکربندی PHP-FPM پارامتر pm.max_children را «سقف درخواست‌هایی که هم‌زمان سرو می‌شوند» تعریف می‌کند. وقتی همه‌ی ورکرها مشغول باشند، روی Apache با mod_proxy_fcgi و روی LiteSpeed پاسخ مستقیماً 503 است؛ اما روی Nginx معمولاً 502 یا 504 می‌گیرید، چون درخواست یا در صف listen.backlog می‌ماند تا fastcgi_read_timeout سر برسد (504) یا connect() با خطای (11: Resource temporarily unavailable) شکست می‌خورد (502). پس اگر روی Nginx هستید و 503 می‌بینید، اشباع استخر مقصر نیست. لاگ FPM اما در هر سه حالت یکسان است و همین آن را به مطمئن‌ترین سرنخ تبدیل می‌کند:

grep -i "max_children\|listening queue" /var/log/php8.4-fpm.log

WARNING: [pool www] server reached pm.max_children setting (12), consider raising it
WARNING: [pool www] listening queue is not empty, #38 requests are waiting to be served, consider raising pm.max_children setting (12)

نسخه را با نسخه‌ی PHP خودتان عوض کنید: مسیر لاگ روی Debian و Ubuntu /var/log/phpX.Y-fpm.log است، روی AlmaLinux و CentOS ‏/var/log/php-fpm/error.log، و روی cPanel زیر /opt/cpanel/ea-phpXY/root/usr/var/log/php-fpm/. دیدن هرکدام از این دو خط یعنی تشخیص قطعی.

برای وضعیت لحظه‌ای، صفحه‌ی وضعیت FPM را با pm.status_path فعال کنید — که به‌تنهایی کافی نیست: در Nginx باید مسیر متناظرش را هم تعریف کنید، وگرنه فقط 404 می‌گیرید.

location = /fpm-status {
    allow 127.0.0.1; deny all;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.4-fpm.sock;
}

سه عدد این صفحه کلیدی است: listen queue یعنی چند درخواست منتظر ورکر آزادند، max active processes بیشترین ورکر هم‌زمان فعال، و max children reached که بزرگ‌تر از صفر بودنش یعنی سقف دست‌کم یک‌بار پر شده. هدر Host را حتماً بدهید، وگرنه درخواست روی وهاست پیش‌فرض می‌نشیند:

curl -s -H 'Host: example.com' http://127.0.0.1/fpm-status

pool:                 www
process manager:      dynamic
listen queue:         38
max listen queue:     129
idle processes:       0
active processes:     12
max active processes: 12
max children reached: 4

max_children عددی دلبخواه نیست، حاصل تقسیم است. هر دو عدد را خودتان روی سرور اندازه بگیرید:

# average resident memory of live PHP-FPM *children* (master excluded), in MB
ps --no-headers -o rss,args -C php-fpm8.4 | awk '/pool /{s+=$1; n++} END {if (n) printf "%d workers, avg %.0f MB\n", n, s/n/1024; else print "no worker found"}'
12 workers, avg 78 MB

# RAM available right now — the running FPM workers are NOT counted as free
free -m | awk '/Mem:/ {print "available:", $7, "MB"}'
available: 1420 MB

فیلتر /pool / ورکرها را از پروسه‌ی master جدا می‌کند؛ بدون آن master هم شمرده می‌شود و میانگین را پایین می‌کشد. و اینجاست که تقریباً همه‌ی فرمول‌های رایج اشتباه می‌کنند: ستون available همان لحظه‌ای اندازه گرفته می‌شود که آن ۱۲ ورکر در حال اجرا و مشغول خوردن حافظه‌اند، پس ۱۴۲۰ «رمِ باقی‌مانده برای PHP» نیست، رمِ باقی‌مانده بعد از آن‌هاست. باید حافظه‌ی ورکرهای فعلی را به آن برگردانید: (۱۴۲۰ + ۱۲×۷۸) ÷ ۷۸ ≈ ۳۰. و چون RSS حافظه‌ی مشترک را در هر ورکر دوباره می‌شمارد، این ۳۰ سخاوتمندانه است نه بدبینانه؛ با حاشیه‌ی پیک MySQL، ۲۰ تا ۲۵ محتاطانه‌تر است. صادقانه‌ترین جمله‌ی این بخش: بالابردن max_children فراتر از حافظه‌ی موجود 503 را درمان نمی‌کند، بدترش می‌کند — سرور سواپ می‌کند و OOM Killer پروسه‌ها را، گاهی خود MySQL را، می‌کشد. اگر عدد درست کوچک‌تر از نیاز واقعی سایت است، مسئله تنظیمات نیست، کمبود رم است؛ راهنمای مانیتورینگ سرور لینوکس آستانه‌های هشدار را پوشش می‌دهد.

خطای 503 در Apache: ورکر mod_proxy در حالت خطا و دیسک پر

برخلاف Nginx که برای بک‌اند مرده 502 می‌دهد، Apache در یک حالت مشخص خطای 503 برمی‌گرداند: وقتی ماژول پراکسی ورکر سالمی برای مبدأ پیدا نکند، پاسخ HTTP_SERVICE_UNAVAILABLE یعنی همان 503 برمی‌گردد و آن ورکر به حالت خطا علامت می‌خورد. ردش در لاگ خطای httpd است: ap_proxy_connect_backend disabling worker for (127.0.0.1:9000) و پشت‌بندش proxy: HTTP: disabled connection for. مکملش در مستندات mod_proxy آمده: پارامتر retry با پیش‌فرض ۶۰ ثانیه تعیین می‌کند تا چه مدت درخواستی به آن مبدأ نرود. یعنی حتی اگر بک‌اند را همین حالا برگردانید، ممکن است تا یک دقیقه هنوز 503 بگیرید — این تأخیر باگ نیست.

systemctl status php8.4-fpm --no-pager
ss -lxp | grep -i php        # unix socket: the default on Debian/Ubuntu and cPanel
ss -lntp | grep ':9000'      # only if the pool listens on TCP
df -h /var /tmp

هر دو دستور ss را با کاربر root بزنید، وگرنه ستون نام پروسه خالی می‌ماند. و حواستان باشد ss -lntp فقط سوکت TCP را نشان می‌دهد؛ خروجی خالی یعنی «روی TCP نیست»، نه «سوکتی وجود ندارد». اگر سرویس اصلاً بالا نمی‌آید فضای دیسک را ببینید: دیسک پر — مخصوصاً پارتیشن لاگ و فایل‌های موقت — سازنده‌ی خاموش بسیاری از 503هاست، چون هیچ سرویسی بدون امکان نوشتن راه نمی‌افتد.

ارور 503 وردپرس بعد از آپدیت: فایل .maintenance جامانده

شایع‌ترین ارور 503 وردپرس بعد از یک به‌روزرسانی ناموفق ساخته می‌شود: وردپرس هنگام هر به‌روزرسانی هسته، افزونه یا پوسته فایلی به نام .maintenance در ریشه‌ی سایت می‌سازد و تا پایان کار همه‌ی بازدیدها را با 503 و پیام «Briefly unavailable for scheduled maintenance» جواب می‌دهد؛ اگر به‌روزرسانی نصفه بماند فایل باقی می‌ماند. تا اینجا را همه گفته‌اند؛ جزئیاتی که مسیر عیب‌یابی را عوض می‌کند در خود کد وردپرس است.

تابع wp_is_maintenance_mode فقط وقتی حالت تعمیر را فعال می‌داند که مقدار $upgrading داخل همان فایل کمتر از ده دقیقه پیش ثبت شده باشد. نتیجه‌ی مستقیم: اگر بیش از ده دقیقه از یک به‌روزرسانی ناموفق گذشته و سایت هنوز 503 می‌دهد، مقصر فایل .maintenance نیست و پاک‌کردنش چیزی را حل نمی‌کند. علامت قطعی این حالت هم در هدرهاست: وردپرس دقیقاً Retry-After: 600 می‌فرستد.

cd /home/user/public_html
cat .maintenance
<?php $upgrading = 1788336000; ?>

# compare that timestamp with now: a gap over 600 seconds means it is already inactive
date +%s
1788339912

rm -f .maintenance

بدون دسترسی SSH هم همین کار انجام می‌شود: با فایل‌منیجر پنل یا یک کلاینت FTP وارد ریشه‌ی سایت شوید و .maintenance را حذف کنید — فایل‌های نقطه‌دار در فهرست ریشه دیده می‌شوند و پیش از حذف می‌توانید همان یک خط $upgrading را باز کنید. در پنل مهران هاست این کار از تب «فایل‌ها»ی همان سرویس انجام می‌شود.

نکته‌ی تکمیلی کمتر شناخته‌شده: اگر فایلی به نام maintenance.php در wp-content بگذارید، وردپرس به‌جای صفحه‌ی پیش‌فرض آن را نمایش می‌دهد — جای درستی برای یک صفحه‌ی فارسی و مرتب، به شرطی که خودتان کد 503 و هدر Retry-After را بفرستید، چون در این مسیر وردپرس هدرهای پیش‌فرضش را نمی‌فرستد و صفحه‌ی شما ممکن است با کد 200 ایندکس شود.

خطای 503 در Nginx: محدودیت نرخ درخواست، ربات‌ها و لایه‌ی لبه

اگر خطای 503 فقط برای بعضی بازدیدکننده‌ها یا روی بعضی مسیرها می‌آید، احتمالاً چیزی عمداً نرخ درخواست را محدود کرده است — و روی Nginx این شایع‌ترین توضیح یک 503 واقعی است، چون رفتار پیش‌فرض همین است: مستندات ماژول‌های limit_req و limit_conn می‌گویند مقدار پیش‌فرض limit_req_status و limit_conn_status هر دو 503 است. یعنی هر قانون محدودیتی که کسی روزی روی سرور گذاشته امروز به شکل 503 خودش را نشان می‌دهد — نحو این دستورها را در راه‌اندازی Nginx روی اوبونتو نوشته‌ایم. و چون سطح لاگ پیش‌فرض limit_req برابر error است، ردش در لاگ خطا هست:

grep "limiting requests" /var/log/nginx/error.log | tail -3

2026/09/02 11:04:18 [error] 918#918: *20431 limiting requests, excess: 0.714 by zone "perip",
  client: 203.0.113.7, server: example.com, request: "GET /?s=test HTTP/2.0", host: "example.com"

سه سناریو پشت این خط‌ها نشسته است. اول، هجوم ربات‌ها و اسکنرها به مسیرهای سنگین مثل جست‌وجوی داخلی و فیلتر فروشگاه؛ اینجا محدودیت نرخ کار درستی می‌کند و مشکل واقعی بی‌دفاع‌بودن آن مسیرهاست — روش شمارش این ترافیک به تفکیک مبدأ در راهنمای پهنای باند سرور آمده. دوم، قانونی که خیلی سخت‌گیرانه نوشته شده و کاربران واقعی — مخصوصاً چند کاربر پشت یک آی‌پی مشترک — را هم می‌گیرد. سوم، محدودیت روی لبه یا CDN، که درخواست اصلاً به سرور شما نمی‌رسد و در لاگ مبدأ ردی ندارد؛ CDN چیست و چطور کار می‌کند مسیر درخواست را از لبه تا مبدأ باز کرده است.

دیتابیس هم می‌تواند خطای 503 بسازد

دیتابیس هیچ‌وقت مستقیماً کد 503 نمی‌فرستد — HTTP را نمی‌فهمد — اما یکی از قابل‌اعتمادترین راه‌های رسیدن به آن است. زنجیره روشن است: کوئری کند یا قفل‌شده هر ورکر PHP را به‌جای دویست میلی‌ثانیه چند ثانیه مشغول نگه می‌دارد؛ استخر پر می‌شود؛ و لایه‌ی جلویی بسته به وب‌سرور 503 (Apache و LiteSpeed) یا 502 و 504 (Nginx) برمی‌گرداند. پس وقتی لاگ FPM از پرشدن max_children خبر می‌دهد، پیش از بالابردن آن عدد یک نگاه به کوئری‌های کند بیندازید.

روی هاست اشتراکی سقف‌های خود MySQL هم در کارند: خطای 1040 با متن «Too many connections» یعنی کل سرور به سقف اتصال رسیده، 1203 یعنی همین کاربر از سقف max_user_connections عبور کرده، و 1226 یعنی یکی از سقف‌های منابع همین کاربر پر شده است. هرکدام در وردپرس به صفحه‌ی «Error establishing a database connection» ختم می‌شود.

و یک واقعیت مهم برای سئو: تابع dead_db آن صفحه را با کد پیش‌فرض 500 می‌فرستد، نه 503 — یعنی خرابی موقت دیتابیس مثل یک خطای داخلی به موتور جست‌وجو معرفی می‌شود، با همه‌ی پیامدهایش. اصلاحش ساده است: فایلی به نام db-error.php در wp-content بسازید. وردپرس آن را در مسیر عادی بارگذاری اجرا نمی‌کند؛ فقط وقتی dead_db صدا زده شود پیش از هر خروجی دیگری require می‌شود و کار همان‌جا تمام می‌شود. پس داخلش به هیچ تابع وابسته به دیتابیس — get_option، get_bloginfo، شورت‌کد — دست نزنید و HTML را ثابت بنویسید.

<?php // wp-content/db-error.php
http_response_code(503);
header('Retry-After: 300');
header('Content-Type: text/html; charset=utf-8');
?>
<!doctype html><html lang="fa" dir="rtl"><meta charset="utf-8">
<title>اختلال موقت</title>
<p>سایت برای دقایقی در دسترس نیست. لطفاً کمی بعد دوباره تلاش کنید.</p>

کاهش فشار روی دیتابیس هم بحث جداگانه‌ای است — کش صفحه، ایندکس‌های درست و کوتاه‌کردن جدول‌های متورم — که مسیر کاملش را در راهنمای افزایش سرعت وردپرس نوشته‌ایم.

503 و سئو: چرا این کد برای توقف برنامه‌ریزی‌شده درست است

برای توقف کوتاه و عمدی سایت — انتقال هاست، مهاجرت دیتابیس، به‌روزرسانی سنگین — کد درست 503 است، نه 500 و نه 404. تفاوتش با 200 این است که گوگل صفحه‌ی «در حال تعمیر» را به‌جای محتوای واقعی ایندکس نمی‌کند، و تفاوتش با 404 این است که نشانی حذف‌شده تلقی نمی‌شود. راهنمای گوگل درباره‌ی متوقف‌کردن موقت کسب‌وکار آنلاین صریح است، اما ترتیبش را وارونه نخوانید: گزینه‌ی اول گوگل این است که سایت آنلاین بماند و فقط امکاناتش محدود شود؛ خارج‌کردن کامل سایت را «اقدامی حاد» می‌داند که «فقط برای مدتی خیلی کوتاه، حداکثر چند روز» جا دارد — و اگر ناچار شدید، صفحه‌ی اطلاع‌رسانی را با کد 503 برگردانید.

هدر Retry-After مکمل ضروری این کد است. طبق بخش Retry-After در RFC 9110 مقدارش یا تعداد ثانیه‌های تأخیر است یا تاریخی به قالب HTTP، و همراه 503 یعنی «سرویس تا این زمان در دسترس نخواهد بود». نمونه‌ی کانفیگ Nginx برای توقفی نیم‌ساعته که آی‌پی خودتان را مستثنا می‌کند:

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/example.com;

    if ($remote_addr != 203.0.113.7) {
        return 503;
    }

    location / { try_files $uri $uri/ /index.php?$args; }

    error_page 503 @maintenance;
    location @maintenance {
        root /var/www/maintenance;
        add_header Retry-After 1800 always;
        try_files /index.html =503;
    }
}

دو خط بالا حذف‌شدنی نیستند: بدون ssl_certificate و کلیدش Nginx اصلاً بالا نمی‌آید، و بدون location / آی‌پیِ مستثناشده به‌جای سایت واقعی 404 می‌گیرد. ضمناً error_page کد اصلی را حفظ می‌کند، پس صفحه‌ی تعمیر با همان 503 سرو می‌شود — با نحو =response ممکن است ناخواسته 200 بدهید و همان صفحه ایندکس شود.

اما محدودیت این کد را هم باید صادقانه گفت. مستندات گوگل درباره‌ی خطاهای HTTP و شبکه می‌گوید در برابر پاسخ‌های 500، 502 و 503 نرخ خزش کاهش می‌یابد و «خط لوله‌ی ایندکس گوگل نشانی‌هایی را که به‌طور مداوم خطای سرور برمی‌گردانند از ایندکس حذف می‌کند». یعنی 503 فقط تا وقتی بی‌خطر است که کوتاه باشد. گوگل در همان راهنمای توقف موقت کسب‌وکار آنلاین صریح‌تر هم هست: بستن کامل سایت «حتی فقط برای چند هفته» می‌تواند روی ایندکس‌شدن سایت اثر منفی بگذارد.

⚠️ 503 را برای بازه‌ی کوتاه و اعلام‌شده به کار ببرید، نه به‌عنوان پارکینگ بلندمدت سایت. اگر پروژه‌ای هفته‌ها متوقف می‌ماند، به‌جای 503 سراسری سایت را با محتوای واقعی و امکانات محدودشده بالا نگه دارید — گزینه‌ی ترجیحی خود گوگل. و 503 ناخواسته‌ی طولانی را یک فوریت سئو حساب کنید، نه خطای فنی معمولی.

علت‌های خطای 503، راه تشخیص قطعی و راه‌حل هرکدام

جمع‌بندی همه‌ی مسیرهایی که به خطای 503 می‌رسند، در یک جدول:

علتراه تشخیص قطعیراه‌حل
پرشدن استخر PHP-FPMخط server reached max_children در لاگ FPM یا listen queue بزرگ‌تر از صفرمحاسبه‌ی max_children از رم در دسترس به‌علاوه‌ی حافظه‌ی ورکرهای فعلی، تقسیم بر حافظه‌ی یک ورکر
سقف حافظه یا پروسه‌ی اکانت در هاست اشتراکیهم‌زمانی خطاها با ساعت اوج، و شمارنده‌های حافظه و پروسه‌ی اکانت در همان بازه — از صفحه‌ی Resource Usage پنل، وگرنه با تیکتکش صفحه، حذف افزونه‌های سنگین و ثبت تیکت با ساعت دقیق
سقف Entry Processes در CloudLinuxکد 508 به‌جای 503 با پیام Resource Limit Is Reachedکاهش زمان اجرای هر درخواست؛ این سقف از سمت مشتری تغییر نمی‌کند
حالت تعمیر جامانده در وردپرسهدر Retry-After برابر 600 و گذشت کمتر از ده دقیقه از آپدیت ناموفقحذف ‎.maintenance از ریشه و تکمیل دستی به‌روزرسانی
محدودیت نرخ درخواست در وب‌سرورخط limiting requests در لاگ خطای Nginx با نام zone و آی‌پیبازبینی قانون limit_req و کش‌کردن مسیرهای پرهزینه
محدودیت یا اختلال روی لایه‌ی لبه503 حتی برای فایل ایستا و نبود هیچ ردی در لاگ مبدأبازبینی محدودیت نرخ یا سپر ترافیک لبه — در بعضی سرویس‌ها یک گزینه‌ی چندحالته است، نه فهرست قانون — و آزمودن مستقیم آی‌پی مبدأ
اشباع یا قطع دیتابیسخطاهای 1040، 1203 یا 1226 و کندی هم‌زمان صفحه‌های دینامیکرفع کوئری‌های کند، ایندکس‌گذاری و افزایش سقف اتصال‌ها
دیسک پر یا سرویس بالا نیامدهخروجی df -h نزدیک صد درصد یا وضعیت failed سرویس PHP-FPMپاک‌سازی لاگ و فایل موقت، سپس راه‌اندازی دوباره‌ی سرویس

وقتی خطای 503 تکرار می‌شود یعنی از هاست اشتراکی بزرگ‌تر شده‌اید

یک الگو را جدی بگیرید: اگر خطای 503 در حمله یا پیک استثنایی نمی‌آید بلکه در ترافیک عادی و همیشه در همان ساعت‌های شلوغ تکرار می‌شود، این خطا نیست؛ پیام است. نیاز هم‌زمانی سایت شما از سقف پلن اشتراکی عبور کرده و هیچ تنظیمی در سمت شما آن را جابه‌جا نمی‌کند. تفاوت دو مدل و نقطه‌ی سربه‌سر مهاجرت را در مقایسه‌ی هاست اشتراکی و سرور مجازی نوشته‌ایم.

مشکل اینجاست که تصمیم مهاجرت عقب می‌افتد، چون کسی نمی‌خواهد برای یک فرضیه یک ماه سرور بخرد. سرور ابری ساعتی همین مانع را برمی‌دارد: یک سرور ابری بسازید — تحویل خودکار است و معمولاً کمتر از ۶۰ ثانیه طول می‌کشد — نسخه‌ای از سایت را رویش بالا بیاورید، استخر PHP-FPM را با فرمول همین مقاله تنظیم کنید و همان ساعت‌های شلوغ را آزمایش کنید.

اگر جواب داد مهاجرت می‌کنید؛ اگر نداد سرور را حذف می‌کنید و هزینه همان چند ساعت است. منطق اقتصادی این مدل را در راهنمای اجاره‌ی ساعتی سرور باز کرده‌ایم. و اگر هنوز مطمئن نیستید مسیر درست مهاجرت است، صفحه‌ی میزبانی وب پلن‌های اشتراکی را به تفکیک محل میزبانی نشان می‌دهد؛ ارتقا به پلن بزرگ‌تر هم با یک تیکت انجام می‌شود، نه از تنظیمات پنل شما.

چک‌لیست ده قدمی رفع خطای 503

خطای 503 خوش‌رفتارترین عضو خانواده‌ی 5xx است: سرور می‌گوید زنده است و فقط ظرفیت یا اجازه ندارد. کافی است لایه‌ها را از بالا به پایین کنار بزنید:

  • هدرهای پاسخ را بخوانید — مقدار server و بود یا نبود Retry-After.
  • ایستا و دینامیک را مقایسه کنید. تصویر 200 و صفحه 503 یعنی وب‌سرور سالم است.
  • کد را دقیق بخوانید. 508 یعنی Entry Processes، 502 یعنی بک‌اند از دسترس خارج شده.
  • وب‌سرور را در تشخیص دخالت دهید. روی Nginx اشباع استخر PHP معمولاً 502 یا 504 می‌دهد، نه 503.
  • لاگ PHP-FPM را گرِپ کنید برای max_children و listening queue.
  • فایل ‎.maintenance را فقط زیر ده دقیقه جدی بگیرید؛ بعد از آن بی‌اثر است.
  • لاگ وب‌سرور را برای خط محدودیت نرخ ببینید. 503 گزینشی یعنی قانونی در کار است.
  • دیسک و حافظه را چک کنید با df -h و free -m.
  • برای توقف عمدی، 503 با Retry-After بفرستید — کوتاه و اعلام‌شده، نه هفته‌ها.
  • تکرار 503 در ترافیک عادی را سیگنال مهاجرت بدانید، نه دعوت به بالابردن عددها.

سؤالات پرتکرار

خطای 503 Service Unavailable یعنی چه؟

خطای 503 Service Unavailable یعنی سرور زنده است اما در این لحظه نمی‌تواند یا نمی‌خواهد پاسخ بدهد و وضعیت موقتی است. استاندارد RFC 9110 علت را «بار موقت یا تعمیرات برنامه‌ریزی‌شده» تعریف می‌کند. در عمل یعنی استخر پردازش PHP پر شده، سقف منابع اکانت پر شده، قانون محدودیت نرخ فعال شده، یا سایت عمداً در حالت تعمیر است.

تفاوت خطای 503 با 500 و 502 در چیست؟

تفاوت خطای 503 با 500 و 502 در این است که در 503 چیزی نشکسته. در 500 اپلیکیشن وسط اجرای کد زمین می‌خورد و مشکل از برنامه یا کانفیگ است؛ در 502 وب‌سرور جلویی از سرویس پشتی پاسخ سالمی نمی‌گیرد یا به آن نمی‌رسد؛ در 503 سرویس سرِ پا است و به دلیل کمبود ظرفیت، محدودیت نرخ یا حالت تعمیر عمداً جواب نمی‌دهد. روی Nginx خاموش‌بودن PHP-FPM معمولاً 502 می‌دهد، نه 503.

خطای 503 وردپرس بعد از آپدیت را چطور رفع کنم؟

خطای 503 وردپرس بعد از آپدیت را با حذف فایل ‎.maintenance رفع می‌کنید، اما فقط اگر کمتر از ده دقیقه از به‌روزرسانی ناموفق گذشته باشد؛ علامت این حالت هدر Retry-After با مقدار ۶۰۰ است. آن فایل را از ریشه‌ی سایت پاک کنید — با SSH، فایل‌منیجر پنل یا FTP — و به‌روزرسانی را از پیشخوان کامل کنید. اگر بیش از ده دقیقه گذشته و سایت هنوز 503 می‌دهد، وردپرس خودش آن فایل را نادیده می‌گیرد و علت جای دیگری است: سقف منابع هاست یا اشباع استخر PHP.

آیا خطای 503 به سئوی سایت آسیب می‌زند؟

خطای 503 کوتاه‌مدت و همراه هدر Retry-After آسیبی نمی‌زند و درست‌ترین کد برای توقف برنامه‌ریزی‌شده است، چون گوگل صفحه‌ی موقت را به‌جای محتوای اصلی ایندکس نمی‌کند. اما طولانی‌شدنش خطرناک است: مستندات گوگل می‌گوید نرخ خزش کاهش می‌یابد و نشانی‌هایی که مداوم خطای سرور برمی‌گردانند از ایندکس حذف می‌شوند.

چطور بفهمم خطای 503 از هاست است یا از CDN و لایه‌ی لبه؟

برای تشخیص اینکه خطای 503 از هاست شماست یا از CDN، هدرهای پاسخ را با یک درخواست GET واقعی ببینید و مقدار server را بخوانید؛ اگر نام سرویس لبه آنجا باشد و هیچ هدری از سرور شما همراهش نیاید، پاسخ روی لبه ساخته شده است. از curl -I پرهیز کنید، چون HEAD می‌فرستد و بعضی سرویس‌های لبه به HEAD جور دیگری جواب می‌دهند. آزمون دوم مقایسه‌ی فایل ایستا با صفحه‌ی دینامیک است: اگر هر دو 503 بگیرند و لاگ مبدأ خالی باشد، درخواست اصلاً به هاست نرسیده است.

آموزش‌های مرتبط

آماده‌ی تمرین عملی هستید؟

سرور ابری ساعتی مهران هاست در ۶۰ ثانیه تحویل می‌شود — تمرین کنید و فقط بابت همان ساعت‌ها پرداخت کنید. هزینه را پیش از ثبت‌نام با محاسبه‌گر برآورد کنید.