Apache و Nginx
رفع خطای 502 Bad Gateway در Nginx
خطای 502 Bad Gateway در Nginx یعنی Nginx به برنامه پشت خودش، مثل PHP-FPM یا یک برنامه Node، وصل نشده یا جواب نامعتبر گرفته است. در بیشتر موارد سرویس پشتی خاموش است یا آدرس سوکت و پورت در کانفیگ با واقعیت نمی خواند، و خط مربوط در error.log علت را نشان می دهد.
وقتی سایتی که پشت Nginx است به جای صفحه، عبارت 502 Bad Gateway نشان می دهد، Nginx خودش بالاست ولی برنامه ای که باید جواب بدهد جواب نمی دهد. این برنامه معمولا PHP-FPM است و گاهی Node، Python یا یک Apache پشت Nginx. فقط روی VPS یا سرور با دسترسی root می توانید این مشکل را خودتان حل کنید. روی هاست اشتراکی، لاگ و سرویس ها دست ادمین است و خطای 502 را باید با تیکت و ذکر ساعت خطا به پشتیبانی بدهید.
خطای 502 دقیقا یعنی چه
Nginx در نقش پروکسی درخواست را به یک upstream می فرستد. 502 یعنی یا اتصال برقرار نشد، یا upstream وسط کار قطع کرد، یا جوابی فرستاد که Nginx نتوانست قبول کند. اگر upstream وصل شد ولی دیر جواب داد، خطا 504 است و رفع خطای 504 Gateway Timeout را باید ببینید.
اول error.log را بخوانید
هر حدسی را با لاگ شروع کنید. فایل پیش فرض /var/log/nginx/error.log است و این دستور خط های تازه را زنده نشان می دهد:
tail -f /var/log/nginx/error.log
در حالی که لاگ باز است، صفحه را یک بار رفرش کنید. خط تازه ای که ظاهر می شود، علت را دارد. جدول زیر رایج ترین خط ها را نشان می دهد.
| خط در error.log | معنی | علت اصلی |
|---|---|---|
connect() to unix:/run/php/php8.2-fpm.sock failed (2: No such file or directory) | فایل سوکت وجود ندارد | PHP-FPM خاموش است یا مسیر سوکت در Nginx اشتباه است |
connect() to unix:... failed (13: Permission denied) | Nginx اجازه خواندن سوکت را ندارد | مالک یا مود سوکت، یا کاربر Nginx |
connect() failed (111: Connection refused) while connecting to upstream | روی آن پورت کسی شنود نمی کند | سرویس پشتی خاموش است یا پورت اشتباه است |
upstream prematurely closed connection while reading response header from upstream | upstream وسط کار بسته شد | کرش یا ریستارت PHP-FPM، کمبود حافظه |
recv() failed (104: Connection reset by peer) | اتصال از طرف upstream ریست شد | همان کرش، یا محدودیت پروسه |
no live upstreams while connecting to upstream | همه سرورهای بلوک upstream از مدار خارج شده اند | سرویس های پشتی خاموش یا خطای مکرر |
upstream sent too big header while reading response header from upstream | هدر جواب از بافر بزرگ تر است | بافر هدر کوچک است |
اگر خط تازه ای در لاگ نمی آید، شاید Nginx لاگ را جای دیگری می نویسد. grep error_log /etc/nginx/nginx.conf /etc/nginx/sites-enabled/* مسیر را نشان می دهد. اگر دامنه پشت Cloudflare است، صفحه 502 را بخوانید: اگر نام Cloudflare دارد، مشکل ممکن است بین Cloudflare و سرور شما باشد و اگر صفحه ساده Nginx است، خطا از خود سرور می آید.
علت اول: PHP-FPM خاموش است
شایع ترین علت، متوقف بودن سرویس PHP-FPM است. بعد از ریبوت، به روزرسانی بسته ها یا کمبود حافظه این اتفاق می افتد. نام سرویس به توزیع و نسخه بستگی دارد: روی Debian و Ubuntu مثل php8.2-fpm و روی AlmaLinux و Rocky معمولا php-fpm.
systemctl status php8.2-fpm
systemctl restart php8.2-fpm
اگر ریستارت جواب داد ولی بعد از مدتی دوباره خاموش شد، علت اصلی را در لاگ PHP-FPM پیدا کنید. روی Debian و Ubuntu مسیر آن معمولا /var/log/php8.2-fpm.log است. برای فعال شدن در بوت systemctl enable php8.2-fpm را بزنید.
برای آشنایی با نسخه و حافظه PHP در هاست cPanel تنظیم نسخه PHP و memory limit در cPanel توضیح داده شده است، ولی روی VPS این مقدارها در فایل php.ini و pool مربوط به FPM تنظیم می شوند.
علت دوم: مسیر سوکت یا پورت در Nginx با FPM نمی خواند
بعد از ارتقای PHP، نام سوکت عوض می شود (مثلا از php8.1-fpm.sock به php8.2-fpm.sock) و Nginx هنوز به سوکت قدیمی اشاره می کند. دو مقدار را کنار هم بگذارید. اول مقدار fastcgi_pass در سایت Nginx:
grep -rn "fastcgi_pass" /etc/nginx/
و بعد مقدار listen در pool مربوط به FPM:
grep -n "^listen" /etc/php/8.2/fpm/pool.d/www.conf
روی AlmaLinux و Rocky pool در /etc/php-fpm.d/www.conf است. دو مقدار باید یکی باشند. مثلا اگر pool با سوکت یونیکس کار می کند، در Nginx باید این خط را داشته باشید:
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
و اگر pool روی TCP است:
fastcgi_pass 127.0.0.1:9000;
با ls -l /run/php/ ببینید سوکت واقعا هست و با ss -ltnp | grep 9000 ببینید روی TCP کسی شنود می کند. بعد از اصلاح مقدار، nginx -t را اجرا کنید و بعد systemctl reload nginx را بزنید.
هر تغییر در کانفیگ Nginx را با nginx -t تست کنید و فقط وقتی syntax is ok و test is successful دیدید reload بزنید. اگر کانفیگ خطا داشته باشد و ریستارت کنید، کل سایت های سرور پایین می آیند. پیش از ویرایش از فایل نسخه پشتیبان بگیرید.
علت سوم: پرمیشن سوکت
اگر در لاگ (13: Permission denied) است، سوکت وجود دارد ولی Nginx اجازه نوشتن در آن را ندارد. Nginx با کاربر www-data (Debian و Ubuntu) یا nginx (RHEL) اجرا می شود. در فایل pool این سه مقدار باید با آن کاربر هماهنگ باشند:
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
روی RHEL به جای www-data از nginx یا apache بر اساس کانفیگ خودتان استفاده کنید. کاربر Nginx را در خط user اول /etc/nginx/nginx.conf می بینید. بعد از تغییر باید FPM را ریستارت کنید. روی سیستم هایی که SELinux فعال است و پرمیشن درست به نظر می رسد، ausearch -m avc -ts recent را اجرا کنید تا ببینید مانع از SELinux است یا نه.
علت چهارم: پروسه های FPM پر شده یا کرش می کنند
اگر خطا فقط وقت پرترافیک می آید یا upstream prematurely closed connection می بینید، لاگ PHP-FPM را نگاه کنید. پیام زیر یعنی همه پروسه های مجاز مشغول بودند:
WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
عدد در پیام همان مقدار فعلی است. pm.max_children را متناسب با حافظه آزاد سرور بالا ببرید. هر پروسه PHP حافظه می خورد و رقم بالا بدون حساب باعث می شود سرور حافظه کم بیاورد. میانگین حافظه هر پروسه را با ps -C php-fpm8.2 -o pid,rss,cmd ببینید و عدد را با حساب تنظیم کنید.
اگر پروسه ها وسط کار می میرند، دو دلیل رایج دارد: کمبود RAM و باگ در یک افزونه PHP یا کد. این دستور نشان می دهد هسته سیستم عامل سرویس را بسته است یا نه:
dmesg -T | grep -i -E "out of memory|killed process"
خطای segfault در لاگ FPM معمولا از یک extension خراب می آید. افزونه ها را یکی یکی غیرفعال کنید تا مقصر پیدا شود. عملکرد دیسک و حافظه VPS هم نقش دارد و در مقایسه NVMe و دیسک های دیگر در VPS می توانید ببینید.
علت پنجم: برنامه Node، Python یا Apache پشت Nginx
اگر به جای fastcgi_pass از proxy_pass http://127.0.0.1:3000; استفاده می کنید، همان منطق را اجرا کنید. مستقیم به آن پورت درخواست بزنید:
curl -I http://127.0.0.1:3000/
اگر پاسخ نداد یا Connection refused گرفتید، برنامه پایین است. وضعیت آن را با systemctl status نام-سرویس یا pm2 status ببینید و لاگ برنامه را بخوانید. اگر Apache پشت Nginx است، رفع بالا نیامدن Apache را بخوانید، چون ممکن است پورت یا کانفیگ آن مشکل داشته باشد.
علت ششم: هدر بزرگ
اگر وردپرس یا برنامه شما کوکی یا هدر بزرگ می فرستد، Nginx با پیام upstream sent too big header 502 می دهد. بافر را در بلوک location یا server بزرگ تر کنید:
fastcgi_buffer_size 16k;
fastcgi_buffers 16 16k;
برای پروکسی به برنامه دیگر نام های proxy_buffer_size و proxy_buffers را به کار ببرید. اگر پس از بزرگ کردن بافر هم خطا ماند، ببینید برنامه چرا هدر بزرگ می فرستد. دلیل رایج، کوکی های زیاد یا حلقه ریدایرکت است.
تست خود PHP-FPM بدون Nginx
برای اینکه بدانید مشکل از FPM است یا از Nginx، کانفیگ FPM را جدا تست کنید. روی Debian و Ubuntu دستور php-fpm8.2 -t و روی خانواده RHEL دستور php-fpm -t درستی فایل های pool را بررسی می کند. اگر خطا دارد، سرویس به همین دلیل بالا نمی آید و Nginx 502 می دهد.
برای دیدن اینکه سوکت واقعا جواب می دهد، می توانید از cgi-fcgi استفاده کنید. اگر آن را نصب ندارید، ساده ترین راه این است که یک فایل info.php با محتوای <?php phpinfo(); در Document Root بگذارید، آن را در مرورگر باز کنید و بلافاصله پاک کنید. اگر این صفحه باز می شود ولی سایت اصلی 502 می دهد، مشکل از همان برنامه است، مثلا یک افزونه یا قالب که پروسه را می کشد.
در وردپرس، افزونه ها را با تغییر نام پوشه wp-content/plugins موقتا غیرفعال کنید. اگر 502 رفت، افزونه ها را یکی یکی برگردانید تا مقصر مشخص شود. برای کدهای PHP که مرتب پروسه را می کشند، php_admin_value[memory_limit] و request_terminate_timeout در pool محدودیت هایی هستند که ممکن است پروسه را قطع کنند. مقدار فعلی آن ها را در www.conf بخوانید و با زمان اجرای واقعی اسکریپت مقایسه کنید.
بعد از رفع، آزمایش کنید
بعد از اصلاح هر چیزی، این ترتیب را رعایت کنید:
nginx -tرا اجرا کنید.systemctl reload nginxرا بزنید.- با
curl -I https://example.com/کد پاسخ را ببینید. tail -n 20 /var/log/nginx/error.logرا بخوانید تا خط تازه ای نیامده باشد.
اگر مسیر های وردپرس 404 می دهند ولی صفحه اصلی باز می شود، مشکل 502 نیست و باید کانفیگ Nginx برای وردپرس و پیوند یکتا را درست کنید. روی هاست اشتراکی cPanel خطای مشابهی که با سهم منابع حساب می آید، 508 است و در رفع خطای 508 Resource Limit Reached توضیح داده شده است. مستندات رسمی دستورهای پروکسی و FastCGI در nginx.org قرار دارد و برای ساخت سرور با دسترسی root می توانید VPS ایران پیکوهاست را ببینید.