← كل المقالات

حل خطأ 502 Bad Gateway في Nginx وPHP-FPM

حل خطأ 502 بين Nginx وPHP-FPM بفحص السجلات والخدمة ومسار Socket والصلاحيات والذاكرة والطلبات البطيئة قبل تغيير المهلات.

يبني بكري عبدالسلام مواقع الويب والتطبيقات والتكاملات ومنتجات ووردبريس، ويوثق مركز بكري التقني القرارات التقنية وراء هذا العمل.

الخلاصة

خطأ 502 يعني أن Nginx لم يحصل على استجابة سليمة من الـupstream. ابدأ برسالة الخطأ الفعلية، ثم افحص PHP-FPM ومسار الاتصال والصلاحيات والموارد بهذا الترتيب.

لا يكشف 502 Bad Gateway السبب وحده. يعني الخطأ أن Nginx حاول الاتصال بالخدمة الخلفية ولم يحصل على استجابة صالحة. في تطبيقات PHP تكون الخدمة غالباً PHP-FPM، وقد يكون السبب مسار Socket خاطئاً أو خدمة متوقفة أو صلاحيات ناقصة أو عملية انهارت أو طلباً بطيئاً.

لا تبدأ برفع كل قيم الـTimeout. سجل وقت الطلب ومساره، ثم ابحث عن الرسالة المقابلة في السجلات.

ابدأ من السجلات لا من التخمين

أعد تنفيذ الطلب مرة واحدة ثم افحص:

sudo tail -n 100 /var/log/nginx/error.log
sudo journalctl -u php8.3-fpm --since "10 minutes ago"
sudo systemctl status php8.3-fpm --no-pager

استبدل php8.3-fpm باسم الخدمة الموجودة على السيرفر. لمعرفة الخدمات المتاحة:

systemctl list-units --type=service | grep -E 'php.*fpm'

رسائل Nginx تعطيك اتجاه التحقيق:

  • No such file or directory: مسار الـSocket في Nginx لا يطابق PHP-FPM.
  • Permission denied: مستخدم Nginx لا يستطيع الوصول إلى الـSocket أو أحد المجلدات الأب.
  • Connection refused: لا توجد خدمة تستمع على العنوان أو المنفذ.
  • upstream timed out: تم الاتصال، لكن PHP-FPM لم يرسل بيانات خلال المهلة.
  • upstream prematurely closed FastCGI stdout: غالباً حدث Fatal Error أو انتهت العملية أو نفدت الموارد.

إن كان الموقع خلف CDN أو Proxy آخر، تأكد أولاً أن Nginx لديك هو مصدر الاستجابة 502.

افحص Nginx وPHP-FPM كلاً على حدة

تحقق من صحة إعداد Nginx:

sudo nginx -t
sudo systemctl status nginx --no-pager

ثم افحص PHP-FPM:

sudo systemctl is-active php8.3-fpm
sudo systemctl restart php8.3-fpm
sudo journalctl -u php8.3-fpm -n 100 --no-pager

قد يعيد الـRestart الموقع للعمل، لكنه لا يشرح سبب التوقف. اقرأ السجل بعده لتعرف إن كانت المشكلة ملف إعداد غير صالح، Extension مفقود، نقص ذاكرة، أو خطأ يتكرر.

يمكن التحقق من إعداد FPM عبر الـBinary المناسب للتوزيعة:

sudo php-fpm8.3 -tt

لا تفترض اسم الإصدار؛ استخدم command -v أو راجع ملف خدمة systemd.

طابق fastcgi_pass مع listen

إذا كان Nginx يستخدم Unix Socket:

location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

فيجب أن يطابق Pool الخاص بـPHP-FPM، وغالباً يوجد في ملف مثل:

; /etc/php/8.3/fpm/pool.d/www.conf
listen = /run/php/php8.3-fpm.sock

اعرض الـSockets والمنافذ الفعلية:

sudo find /run/php -maxdepth 1 -type s -ls
sudo ss -ltnp | grep php

عند استخدام TCP يجب أن يتطابق الطرفان، مثلاً 127.0.0.1:9000. لا تجعل PHP-FPM يستمع على واجهة عامة.

بعد التعديل:

sudo nginx -t && sudo systemctl reload nginx
sudo systemctl restart php8.3-fpm

أصلح الصلاحيات من المصدر

عند ظهور Permission denied اعرف مستخدم Nginx وملكية الـSocket:

ps -o user,group,cmd -C nginx
sudo stat /run/php/php8.3-fpm.sock

اضبط Pool بدلاً من تنفيذ chmod مؤقت يختفي مع إعادة التشغيل:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

قد يكون المستخدم nginx في بعض التوزيعات. راجع أيضاً صلاحية المرور داخل المجلدات الأب. استخدام 0777 ليس حلاً آمناً.

افحص الضغط والذاكرة والطلبات البطيئة

إذا ظهر 502 أثناء الضغط فقط:

free -h
df -h
sudo dmesg -T | grep -i -E 'out of memory|killed process'
sudo journalctl -u php8.3-fpm -p warning --since today

راجع pm.max_children بناءً على استهلاك العملية الحقيقي والذاكرة المتاحة. رفع العدد بلا حساب قد يجعل Kernel يقتل PHP Processes ويزيد المشكلة.

إن كان الطلب ينفذ تقريراً ثقيلاً أو ينتظر API خارجية، فعّل Slow Log مؤقتاً وافحص التطبيق وقاعدة البيانات. الأعمال الطويلة غالباً أنسب داخل Queue؛ راجع حل مشكلة Laravel Queue وإعداد Supervisor.

لا ترفع fastcgi_read_timeout إلا بعد إثبات أن Endpoint شرعي يحتاج زمناً أطول. وفق توثيق Nginx، القيمة تقيس الزمن بين عمليتي قراءة متتاليتين من FastCGI وليست مهلة كلية للطلب.

تأكد من نجاح الحل

اختبر Health Endpoint والمسار الذي كان يفشل:

curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' \
  https://example.com/health

curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' \
  https://example.com/original-path

تأكد من الآتي:

  1. nginx -t ينجح.
  2. تبقى خدمتا Nginx وPHP-FPM في حالة Active.
  3. لا تظهر رسالة upstream جديدة في السجل.
  4. لا تعود المشكلة بعد Deploy أو Restart.
  5. المراقبة تفحص الموقع وحالة PHP-FPM والذاكرة.

أخطاء شائعة ومنع التكرار

أكثر الأخطاء شيوعاً: ربط Nginx بـSocket لإصدار PHP قديم، تعديل الصلاحيات يدوياً، رفع المهلات كلها، وتشغيل عدد Workers أكبر من قدرة الذاكرة.

ضع إعدادات Nginx وPHP-FPM في Version Control، واختبرها أثناء النشر، وراقب زمن upstream ومعدل 5xx. تكمل قائمة مراجعة Nginx Reverse Proxy الصورة التشغيلية.

أسئلة شائعة

هل انتهت المشكلة إذا اختفى 502 بعد Restart؟

عادت الخدمة، لكن السبب قد يتكرر. راجع السجل قبل Restart والذاكرة وPool Limits وأحداث النشر حتى تعرف لماذا توقفت PHP-FPM.

هل أستخدم Unix Socket أم TCP بين Nginx وPHP-FPM؟

كلاهما صالح. Socket شائعة داخل Host واحدة، وTCP أوضح بين Containers. الأهم Listener خاصة وإعداد متطابق وصلاحيات ومراقبة صحيحة.

مراجع رسمية

لديك سؤال عن هذا الدليل أو فكرة لتعاون تقني؟ تواصل مع بكري عبر المركز التقني.

نهاية الملاحظة.