رفع مشکل

خطای 502 Bad Gateway در Nginx؛ از خواندن لاگ تا رفع قطعی مشکل

تهیه: کلودیفای (نگارش با کمک هوش مصنوعی) · انتشار: · زمان مطالعه: ۷ دقیقه

502502BadGatewayرفع مشکلخطای 502 Bad Gateway درNginx؛ از خواندن لاگ تا رفعقطعی مشکلمجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

خطای 502 یعنی Nginx درخواست را به برنامهٔ پشتی (PHP-FPM، Node.js، پایتون یا کانتینر) فرستاده اما پاسخ معتبری نگرفته است. اولین قدم خواندن /var/log/nginx/error.log است؛ پیام‌هایی مثل connect() failed، Connection refused یا upstream prematurely closed مستقیم علت را نشان می‌دهند. بیشتر وقت‌ها برنامهٔ پشتی متوقف شده، آدرس یا سوکت در proxy_pass اشتباه است، مجوز سوکت درست نیست یا برنامه به‌دلیل کمبود رم kill شده است.

خطای 502 دقیقاً یعنی چه؟

Nginx در بیشتر سرورها نقش «دروازه» یا Reverse Proxy را دارد: درخواست کاربر را می‌گیرد و آن را به برنامه‌ای که پشتش است می‌فرستد. این برنامه ممکن است PHP-FPM برای وردپرس و لاراول، Gunicorn برای جنگو، یک برنامهٔ Node.js یا یک کانتینر داکر باشد. وقتی Nginx نتواند به این برنامه وصل شود یا پاسخ نامعتبر و ناقص بگیرد، به کاربر خطای 502 Bad Gateway نشان می‌دهد.

پس نکتهٔ کلیدی این است: خطای 502 تقریباً هیچ‌وقت مشکل خود Nginx نیست؛ Nginx فقط پیام‌رسان است و می‌گوید «پشت من کسی جواب نمی‌دهد». عیب‌یابی باید روی ارتباط Nginx با برنامهٔ پشتی (Upstream) متمرکز شود.

خطای 502 کجا رخ می‌دهد
درخواست HTTPپاسخ ندارد ⇠ 502کاربرمرورگرNginxReverse Proxyبرنامهٔ پشتیPHP-FPM / Node / Gunicornدرخواست HTTPپاسخ ندارد ⇠ 502کاربرمرورگرNginxReverse Proxyبرنامهٔ پشتیPHP-FPM / Node / Gunicorn
شکل ۱ Nginx سالم است اما برنامهٔ پشت آن متوقف، در آدرس دیگری یا بدون مجوز است؛ نتیجه خطای 502 برای کاربر است.

اگر سایت شما پشت CDN است، ممکن است خطای 502 را خود CDN نشان دهد، نه Nginx سرور شما. در این حالت ابتدا مطمئن شوید سرور اصلی مستقیم پاسخ می‌دهد؛ راهنمای خطاهای 5xx در CDN تفاوت این دو حالت را توضیح می‌دهد.

گام اول: لاگ خطای Nginx را بخوانید

هر عیب‌یابی 502 باید با لاگ شروع شود. پیام لاگ معمولاً علت را دقیقاً نام می‌برد:

sudo tail -n 50 /var/log/nginx/error.log
# یا دنبال کردن زنده هنگام باز کردن صفحه
sudo tail -f /var/log/nginx/error.log

پیام‌های رایج و معنایشان:

پیام در لاگ معنی
connect() failed (111: Connection refused) برنامهٔ پشتی روی آن پورت در حال اجرا نیست
connect() to unix:/run/php/... failed (2: No such file or directory) مسیر سوکت PHP-FPM اشتباه است یا سرویس متوقف شده
connect() to unix:... failed (13: Permission denied) کاربر Nginx اجازهٔ دسترسی به سوکت را ندارد
upstream prematurely closed connection برنامه وسط پاسخ از کار افتاد یا اتصال را بست
upstream sent too big header هدر پاسخ از بافر Nginx بزرگ‌تر است
no live upstreams همهٔ سرورهای پشتی تعریف‌شده از دسترس خارج‌اند

علت ۱: برنامهٔ پشتی اجرا نمی‌شود

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

sudo systemctl status php8.3-fpm     # نسخهٔ PHP خود را بنویسید
sudo systemctl status myapp          # سرویس برنامهٔ خودتان
docker ps -a                          # اگر برنامه در کانتینر است

اگر سرویس متوقف است، لاگش را ببینید تا بفهمید چرا از کار افتاده و بعد اجرایش کنید:

sudo journalctl -u myapp -n 100 --no-pager
sudo systemctl restart myapp

برای اینکه برنامه پس از خطا یا ری‌استارت سرور خودکار بالا بیاید، باید آن را به‌صورت سرویس systemd با Restart=always تعریف کنید؛ نمونهٔ کامل را در اجرای دائمی برنامه با systemd ببینید.

علت ۲: آدرس، پورت یا سوکت اشتباه

مقداری که در proxy_pass یا fastcgi_pass نوشته‌اید باید دقیقاً با جایی که برنامه گوش می‌دهد یکی باشد. ابتدا ببینید برنامه واقعاً روی کجا گوش می‌دهد:

sudo ss -tlnp | grep -E "8000|3000|9000"
ls -l /run/php/

سپس با پیکربندی Nginx مقایسه کنید. چند اشتباه رایج:

  • برنامه روی 127.0.0.1:3000 است اما در Nginx پورت 8000 نوشته شده.
  • PHP به نسخهٔ جدید ارتقا یافته و نام سوکت از php8.1-fpm.sock به php8.3-fpm.sock تغییر کرده، ولی Nginx هنوز آدرس قدیمی را دارد.
  • برنامه داخل کانتینر روی 127.0.0.1 گوش می‌دهد و از بیرون کانتینر در دسترس نیست؛ داخل کانتینر باید روی 0.0.0.0 گوش دهد و پورت منتشر شود.

پس از اصلاح پیکربندی، همیشه پیش از بارگذاری دوباره آن را تست کنید:

sudo nginx -t && sudo systemctl reload nginx

درستی ارتباط را می‌توانید بدون Nginx هم تست کنید: curl -I http://127.0.0.1:8000. اگر این دستور جواب ندهد، مشکل در برنامه است نه Nginx.

root@server: ~
$ tail -n 2 /var/log/nginx/error.log... connect() failed (111: Connection refused) while connecting    to upstream, upstream: "http://127.0.0.1:8000/"$ ss -tlnp | grep 8000$ systemctl status myapp --no-pager | head -n 3   Active: failed (Result: exit-code)$ 
شکل ۲ لاگ می‌گوید اتصال به پورت ۸۰۰۰ رد شده، ss نشان می‌دهد کسی روی آن گوش نمی‌دهد و systemctl علت را تأیید می‌کند.

علت ۳: مجوز دسترسی به سوکت

وقتی Nginx و برنامه از طریق سوکت یونیکس (فایل .sock) با هم صحبت می‌کنند، کاربر Nginx (معمولاً www-data) باید اجازهٔ خواندن و نوشتن روی آن فایل را داشته باشد. در PHP-FPM این تنظیم در فایل pool است:

; /etc/php/8.3/fpm/pool.d/www.conf
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

برای Gunicorn یا برنامه‌های دیگر هم کاربری که برنامه را اجرا می‌کند و گروه سوکت را بررسی کنید. اگر SELinux فعال است (در AlmaLinux و Rocky)، ممکن است اتصال Nginx به شبکه را مسدود کند؛ با setsebool -P httpd_can_network_connect 1 این اجازه داده می‌شود.

علت ۴: کمبود رم و kill شدن برنامه

اگر خطای 502 به‌صورت گاه‌به‌گاه و در ساعت‌های شلوغ رخ می‌دهد و پیام upstream prematurely closed در لاگ است، احتمال زیادی دارد که برنامه به‌دلیل کمبود رم توسط هسته kill شده باشد:

sudo dmesg -T | grep -i -E "killed process|out of memory"
free -h

راه‌حل‌ها: کاهش تعداد پردازش‌های هم‌زمان (مثلاً pm.max_children در PHP-FPM یا تعداد workerهای Gunicorn) متناسب با رم، افزودن Swap به‌عنوان حاشیهٔ امن و در نهایت ارتقای رم. توضیح کامل در کمبود رم سرور و خطای Out of Memory آمده است.

علت ۵: هدر بزرگ و تنظیمات بافر

برخی برنامه‌ها، به‌خصوص وقتی کوکی‌های زیاد یا هدرهای بزرگ می‌فرستند، باعث پیام upstream sent too big header می‌شوند. افزایش بافر در بلوک مربوط مشکل را حل می‌کند:

proxy_buffer_size 16k;
proxy_buffers 8 16k;
# برای PHP-FPM:
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;

حالت‌های خاص: داکر و CDN

برنامه در کانتینر داکر: وقتی Nginx روی خود سرور نصب است و برنامه در کانتینر، بررسی کنید پورت کانتینر واقعاً منتشر شده باشد (docker ps ستون PORTS را نشان می‌دهد). اگر Nginx هم در کانتینر است، آدرس 127.0.0.1 به خود کانتینر Nginx اشاره می‌کند، نه برنامه؛ هر دو را در یک شبکهٔ داکر قرار دهید و در proxy_pass از نام سرویس استفاده کنید. همچنین پس از هر بار ساخت دوباره، کانتینر ممکن است آی‌پی داخلی جدیدی بگیرد؛ استفاده از نام سرویس به‌جای آی‌پی این مشکل را از بین می‌برد.

سایت پشت CDN: اگر بازدیدکننده صفحهٔ خطای 502 با طراحی CDN می‌بیند، ابتدا از روی خود سرور با curl -I http://127.0.0.1 و سپس از بیرون با آی‌پی مستقیم سرور تست کنید. اگر سرور مستقیم پاسخ درست می‌دهد، مشکل در اتصال CDN به سرور است؛ مثلاً فایروال آی‌پی‌های CDN را بسته، پورت یا حالت SSL در تنظیمات CDN اشتباه است یا گواهی سرور منقضی شده است.

تفاوت 502 با 504

خطای 504 (Gateway Timeout) یعنی Nginx به برنامه وصل شده اما برنامه در زمان مقرر پاسخ نداده است؛ معمولاً به‌خاطر کوئری کند دیتابیس یا پردازش طولانی. در حالی که 502 یعنی اتصال اصلاً برقرار نشده یا پاسخ نامعتبر بوده است. این تمایز مهم است، چون راه‌حل 504 معمولاً بهینه‌سازی برنامه یا افزایش timeout است، نه بررسی پورت و سوکت.

502 یا 504؟
502 Bad Gateway
  • اتصال به بک‌اند برقرار نشد
  • یا پاسخ نامعتبر و ناقص بود
  • علت: سرویس متوقف، پورت یا سوکت اشتباه، مجوز
  • راه‌حل: اجرای سرویس و اصلاح آدرس
در برابر
504 Gateway Timeout
  • اتصال برقرار شد
  • اما پاسخ در زمان مقرر نرسید
  • علت: کوئری یا پردازش کند
  • راه‌حل: بهینه‌سازی یا افزایش timeout
شکل ۳ تشخیص درست کد خطا نصف راه حل است.

چک‌لیست سریع رفع 502

  1. error.log را بخوانید و پیام دقیق را پیدا کنید.
  2. وضعیت سرویس برنامه را با systemctl یا docker ps بررسی کنید.
  3. با ss -tlnp و curl مطمئن شوید برنامه روی آدرس درست پاسخ می‌دهد.
  4. proxy_pass یا fastcgi_pass را با آدرس واقعی مقایسه کنید و nginx -t بگیرید.
  5. مجوز سوکت و SELinux را بررسی کنید.
  6. لاگ هسته را برای kill شدن به‌دلیل کمبود رم ببینید.

اگر پیکربندی Nginx را تازه انجام داده‌اید، آموزش Nginx و گواهی Let's Encrypt نمونهٔ پیکربندی درست را نشان می‌دهد. و اگر سرور شما مدام زیر بار کم می‌آورد، شاید وقت ارتقای منابع رسیده باشد؛ پلن‌های سرور مجازی ایران کلودیفای ساعتی هستند و می‌توانید پلن بزرگ‌تر را بدون تعهد ماهانه امتحان کنید.

سؤالات متداول

خطای 502 از سمت سرور است یا کاربر؟

تقریباً همیشه از سمت سرور است. پاک کردن کش مرورگر یا عوض کردن اینترنت کاربر معمولاً اثری ندارد، چون Nginx نتوانسته پاسخی از برنامهٔ پشتی بگیرد. علت را باید در لاگ سرور جست‌وجو کرد.

چرا بعد از ارتقای PHP خطای 502 گرفتم؟

با ارتقای PHP نام سرویس و مسیر سوکت عوض می‌شود. اگر fastcgi_pass در پیکربندی Nginx هنوز به سوکت نسخهٔ قبلی اشاره کند، اتصال برقرار نمی‌شود. مسیر را با ls /run/php پیدا و در Nginx اصلاح کنید.

خطای 502 فقط گاهی رخ می‌دهد؛ علتش چیست؟

خطای متناوب معمولاً به کمبود منابع مربوط است: برنامه در اوج بار به‌دلیل کمبود رم kill می‌شود یا تعداد workerها کافی نیست. لاگ هسته و مصرف رم را در همان ساعت‌ها بررسی کنید.

ری‌استارت Nginx خطای 502 را رفع می‌کند؟

معمولاً نه، چون مشکل در برنامهٔ پشتی است. ری‌استارت برنامه مثل PHP-FPM یا سرویس Node.js ممکن است موقتاً مشکل را حل کند، اما باید علت توقف آن را از لاگ پیدا کنید تا تکرار نشود.

آماده‌اید؟ سرورتان را بسازید.

از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی

سرورتان را همین حالا بسازید.

ساعتی بپردازید. هر وقت خواستید حذف کنید.