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 upstreamupstream وسط کار بسته شدکرش یا ریستارت 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 بخوانید و با زمان اجرای واقعی اسکریپت مقایسه کنید.

بعد از رفع، آزمایش کنید

بعد از اصلاح هر چیزی، این ترتیب را رعایت کنید:

  1. nginx -t را اجرا کنید.
  2. systemctl reload nginx را بزنید.
  3. با curl -I https://example.com/ کد پاسخ را ببینید.
  4. tail -n 20 /var/log/nginx/error.log را بخوانید تا خط تازه ای نیامده باشد.

اگر مسیر های وردپرس 404 می دهند ولی صفحه اصلی باز می شود، مشکل 502 نیست و باید کانفیگ Nginx برای وردپرس و پیوند یکتا را درست کنید. روی هاست اشتراکی cPanel خطای مشابهی که با سهم منابع حساب می آید، 508 است و در رفع خطای 508 Resource Limit Reached توضیح داده شده است. مستندات رسمی دستورهای پروکسی و FastCGI در nginx.org قرار دارد و برای ساخت سرور با دسترسی root می توانید VPS ایران پیکوهاست را ببینید.