خطای 502 Bad Gateway یعنی Nginx در نقش gateway یا proxy نتوانسته پاسخ معتبر و قابلاستفادهای از سرویس بالادست بگیرد. این سرویس ممکن است PHP-FPM، یک اپلیکیشن، Apache یا container باشد. خود صفحه 502 علت را نشان نمیدهد؛ restart کورکورانه شاید سایت را موقتاً بالا بیاورد، اما شواهد لازم برای فهمیدن crash، socket اشتباه یا کمبود ظرفیت را از بین میبرد.
پاسخ سریع: یک زمان دقیق و URL خطادار ثبت کنید، سپس error log همان Nginx و وضعیت upstream را در همان لحظه بررسی کنید. اگر upstream متوقف است علت توقف را از log و memory pressure پیدا کنید؛ اگر فعال است، socket/port، permission و config مؤثر را تطبیق دهید. پیش از reload، syntax را با nginx -t بسنجید.
ابتدا دامنه خرابی را مشخص کنید
- همه URLها 502 هستند یا فقط مسیرهای PHP/API؟
- خطا دائم است یا فقط هنگام ترافیک بالا رخ میدهد؟
- فایل static مثل تصویر باز میشود؟
- از خود سرور و از اینترنت نتیجه یکسان است؟
- آیا درست بعد از deploy، update یا تغییر config شروع شده است؟
اگر فایل static سالم اما صفحه PHP خطاست، مسیر Nginx تا PHP-FPM مظنون اصلی است. اگر فقط یک API خطا میدهد، upstream همان route را بررسی کنید. خطای متناوب معمولاً با ظرفیت، crash دورهای، backend ناسالم در pool یا مشکل شبکه سازگارتر از یک اشتباه ثابت در syntax است.
فرق 502 با 504 چیست؟
در 502، gateway معمولاً اتصال upstream را برقرار نکرده، اتصال زود بسته شده یا پاسخ نامعتبر دریافت کرده است. در 504 Gateway Timeout اتصال یا پردازش بیش از مهلت مجاز طول کشیده است. این مرز مطلق نیست و متن error log تعیینکنندهتر از شماره صفحه است. راهنمای رفع خطای 504 روی timeout و پردازش طولانی تمرکز دارد.
شواهدی که قبل از تغییر باید نگه دارید
زمان همراه timezone، URL، method، status، request ID و آخرین تغییر را ثبت کنید. اگر reverse proxy یا CDN دیگری جلوی Nginx است، مشخص کنید صفحه خطا را کدام لایه تولید کرده است. headerها و ظاهر صفحه فقط سرنخاند؛ log لایهها را با timestamp مشترک تطبیق دهید. cookie، token و داده مشتری را در تیکت عمومی کپی نکنید.
بررسی کمریسک وضعیت
systemctl status nginx --no-pager
systemctl --failed
ss -lntp
free -h
df -h
df -i
این فرمانها عمدتاً وضعیت را میخوانند. نام سرویس PHP-FPM به توزیع و نسخه PHP وابسته است؛ آن را از unitهای موجود یا config واقعی پیدا کنید و حدس نزنید. دیسک یا inode پر میتواند socket، log یا فایل موقت را مختل کند. فشار حافظه نیز ممکن است upstream را بهوسیله OOM Killer متوقف کرده باشد.
Error Log Nginx را بخوانید
مسیر log را از config مؤثر پیدا کنید. پیامهایی مانند connection refused، نبودن فایل socket، permission denied، prematurely closed connection یا upstream sent invalid response هرکدام مسیر متفاوتی دارند. فقط آخرین خط را جدا نکنید؛ host، upstream، request و چند خط پیرامون همان timestamp را ببینید.
- Connection refused: سرویس روی port مورد انتظار گوش نمیدهد یا در حال restart است.
- No such file or directory: socket ساخته نشده یا مسیر config قدیمی است.
- Permission denied: user وبسرور به socket یا مسیر والد دسترسی ندارد.
- Upstream closed connection: برنامه crash کرده، limit خورده یا پاسخ را زود بسته است.
- Invalid header: سرویس پروتکل یا پاسخ مورد انتظار proxy را تولید نکرده است.
آیا Upstream واقعاً در دسترس است؟
برای upstream شبکهای، listener را با ss و یک درخواست محلی کنترلشده بررسی کنید. برای Unix socket، وجود، مالکیت و permission مسیر را ببینید. تست محلی باید Host و protocol درست داشته باشد؛ درخواست HTTP به portی که FastCGI صحبت میکند آزمون معتبری نیست. در Docker نیز localhost داخل container با host یا container دیگر یکی نیست.
PHP-FPM: رایجترین سناریوی وردپرس
وضعیت unit، journal و log pool را در همان بازه بررسی کنید. ممکن است PHP-FPM فعال باشد ولی همه workerها درگیر، pool اشتباه، socket متفاوت یا فرایندها پیدرپی crash شوند. active (running) بهتنهایی سلامت درخواست را ثابت نمیکند. صف، تعداد active/idle process، slow log و مدت درخواستها تصویر بهتری میدهند.
Socket یا TCP؟
مقدار fastcgi_pass در Nginx باید دقیقاً با listen در pool متناظر باشد. پس از ارتقای PHP، نام socket ممکن است تغییر کند و Nginx هنوز به مسیر نسخه قبل اشاره کند. symlink ساختن برای پنهان کردن اختلاف نسخه راهحل پایدار نیست؛ config فعال و lifecycle سرویس را هماهنگ کنید.
Permission Socket
مالک، گروه و mode socket باید اجازه اتصال user Nginx را بدهند. راهحل عمومی chmod 777 امنیت را تضعیف میکند و بعد از restart نیز ممکن است از بین برود. تنظیم مالکیت را در config خود pool اصلاح و سپس با کمترین دسترسی لازم آزمایش کنید.
Crash و OOM را از قلم نیندازید
اگر PHP یا برنامه ناگهان ناپدید شده، journal kernel و سرویس را برای OOM، segfault و exit code بررسی کنید. افزایش خودکار worker بدون محاسبه حافظه میتواند OOM را بیشتر کند. ابتدا memory هر process، سقف container/systemd و ترافیک همزمان را بسنجید؛ بعد ظرفیت pool را تغییر دهید.
وقتی 502 فقط زیر بار رخ میدهد
نرخ خطا را کنار request rate، latency، worker queue، CPU، RAM و dependencyها قرار دهید. دیتابیس کند یا API بیرونی میتواند workerها را نگه دارد تا pool ظرفیت پذیرش نداشته باشد. افزایش worker تنها وقتی مفید است که RAM و CPU کافی باشد؛ وگرنه swapping و crash بیشتر میشود.
Proxy Chain و Docker
در زنجیره CDN → Nginx → container → برنامه، هر hop نام، port، network و health مستقل دارد. نام سرویس Docker فقط در network مربوط resolve میشود و published port با container port تفاوت دارد. IP ثابت container را hard-code نکنید. وضعیت container، restart count، health و log برنامه را کنار proxy log بررسی کنید.
بعد از Deploy چه چیزهایی محتملترند؟
- نام یا port سرویس تغییر کرده ولی proxy config قدیمی است
- PHP-FPM جدید socket دیگری ساخته است
- فایل environment یا secret در دسترس برنامه نیست
- migration دیتابیس شکست خورده و process خارج میشود
- مالکیت فایل یا socket در image جدید متفاوت است
- healthcheck زودتر از آماده شدن واقعی سرویس موفق میشود
در این وضعیت، diff release و log startup از restartهای پیاپی مفیدتر است. اگر rollback تعریفشده و آزموده دارید، بازگشت کنترلشده میتواند سرویس را احیا کند؛ اما داده نوشتهشده و سازگاری migration باید پیش از rollback بررسی شود.
ترتیب اصلاح از کمریسک تا پیشرفته
- دامنه و زمان خطا را ثبت و logها را حفظ کنید.
- وضعیت upstream، listener، disk و memory را بخوانید.
- config مؤثر Nginx را با upstream واقعی تطبیق دهید.
- syntax را با
sudo nginx -tبررسی کنید. - اگر config درست است، علت توقف upstream را رفع و آن را کنترلشده start کنید.
- reload یا restart را فقط برای تغییر لازم انجام دهید.
- از داخل و بیرون، static، dynamic، login و تراکنش اصلی را smoke test کنید.
- پس از احیا، علت ریشهای و اقدام پیشگیرانه را ثبت کنید.
چه کارهایی نکنیم؟
- پاک کردن log یا restart مداوم پیش از جمعآوری شواهد
- بزرگ کردن timeout برای خطای connection refused
- دادن permission عمومی به socket و فایلها
- افزایش بیمحاسبه workerهای PHP
- اعتماد به status سرویس بدون درخواست واقعی
- ویرایش config production بدون backup و syntax test
- نسبت دادن هر 502 به Nginx، بدون بررسی upstream
پیشگیری از بازگشت خطا
برای endpoint واقعی healthcheck، نرخ 502، restart سرویس، queue، memory، disk و certificate alert تعریف کنید. deploy باید config test، readiness واقعی و rollback داشته باشد. نام socket یا سرویس را در automation از منبع واحد بسازید. logها را rotate کنید و request ID را میان proxy و برنامه عبور دهید.
چه زمانی مداخله تخصصی لازم است؟
اگر 502 متناوب است، چند proxy دارید یا restart فقط چند دقیقه اثر میکند، آزمون بیشتر روی production ممکن است قطعی را طولانی کند. مدیریت ماهانه سرور میتواند correlation لاگ Nginx، PHP-FPM، سیستم و دیتابیس را انجام دهد و علت را پیش از تغییر ظرفیت مشخص کند.
پرسشهای متداول
آیا restart کردن Nginx خطای 502 را رفع میکند؟
فقط در بعضی خرابیها و معمولاً موقت. اگر upstream متوقف یا آدرس آن اشتباه باشد، restart Nginx علت را برطرف نمیکند.
چرا بعد از ارتقای PHP خطای 502 میبینم؟
یکی از علتهای رایج اختلاف socket یا pool نسخه جدید با fastcgi_pass فعال است؛ service و config واقعی را تطبیق دهید.
آیا 502 به معنی خرابی دیتابیس است؟
نه الزاماً. دیتابیس میتواند باعث crash یا توقف طولانی برنامه شود، اما 502 مستقیماً درباره ارتباط gateway و upstream است.
چرا فقط بعضی درخواستها 502 میشوند؟
ممکن است یک backend ناسالم، route متفاوت، crash وابسته به داده یا اشباع متناوب pool وجود داشته باشد؛ request ID و upstream انتخابشده را بررسی کنید.