تقديم المحتوى الثابت وخلفيات PHP والتطبيقات
تقديم المحتوى الثابت وخلفيات PHP والتطبيقات
يتميز Nginx في أداء مهمتين مختلفتين جذريًا: إرسال الملفات مباشرةً من القرص بأقصى سرعة ممكنة، والعمل كبوابة ذكية تُحيل الطلبات الديناميكية إلى عملية تطبيق. إتقان هذا التمييز ومعرفة المسار الذي يسلكه كل طلب هو المهارة الجوهرية التي تُفرّق بين مهندس DevOps قادر على تشخيص حركة مرور الإنتاج وآخر لا يعدو نسخ الإعدادات من الإنترنت.
كيف يحدد Nginx ما يفعله بالطلب
كل طلب وارد يصطدم بأولًا بـمحرك مطابقة الموقع (Location Matching) في Nginx. يقيّم Nginx عنوان URI مقابل كتل location وفق ترتيب أولوية صارم: المطابقة التامة (=)، ثم البادئة المفضّلة (^~)، ثم التعابير النمطية (~ و~*)، وأخيرًا مطابقة البادئة العادية. الكتلة الفائزة تحدد ما إذا كانت المعالجة محلية (ملف ثابت) أم بالإحالة إلى خلفية ديناميكية.
الموجهان اللذان يتحكمان في التوزيع هما:
root/alias— يربطان عنوان URI بمسار على القرص ويُقدّم Nginx الملف مباشرةً. لا عمليات تطبيق متورطة إطلاقًا.fastcgi_pass/proxy_pass— يُحيلان الطلب إلى عملية منفصلة (PHP-FPM أو Gunicorn أو Node.js أو Laravel Octane) ويُعيدان تدفق الاستجابة إلى العميل.
تقديم المحتوى الثابت
النمط المعياري للموقع الثابت أو الجزء الأصولي من تطبيق ويب يبدو هكذا. يُحدد الموجه root المسار الأساسي؛ يُضيف Nginx عنوان URI إليه للحصول على المسار الكامل للملف.
تفاصيل جوهرية يجب استيعابها:
try_files $uri $uri/ =404— يتحقق Nginx من وجود الملف ثم المجلد (مع الفهرس)، ويُعيد 404 صريحًا بدلًا من الانتقال لكتلة أخرى. أنهِ دائمًا كتل الثابت بهذه الطريقة.expires 1y; add_header Cache-Control "public, immutable"— للأصول المُبصومة بالمحتوى (اسم الملف يحتوي على هاش)، وجّه المتصفحات وشبكات CDN لتخزينها للأبد. يتغير هاش الملف عند تغيير المحتوى، لذا لا خطر من ذاكرة تخزين قديمة.access_log off— طلبات الأصول قد تُمثل 80% من سجلات الوصول مع قيمة تشخيصية تكاد تعدم. إيقافها يُقلل كتابات القرص ويُبقي سجلاتك مقروءة.
الإحالة إلى خلفية PHP عبر FastCGI
لا يتحدث PHP بروتوكول HTTP مباشرةً — بل يتحدث FastCGI، وهو بروتوكول ثنائي مُصمَّم لعمليات العمّال طويلة الأمد. يُشغّل PHP-FPM (مدير عمليات FastCGI) مجموعة من عمّال PHP يستمعون على Unix socket (أو منفذ TCP). يُترجم Nginx كل طلب HTTP إلى رسالة FastCGI، يُرسلها إلى FPM، ويُعيد تدفق الاستجابة إلى العميل.
try_files $uri =404 داخل location ~ \.php$، سيُمرر Nginx طلبات ملفات PHP غير موجودة إلى FPM على أي حال. قد ينفّذ FPM عندها ملف PHP مضمّنًا في صورة مُرفوعة (مثل uploads/shell.jpg/../../evil.php). هذه كانت ثغرة اجتياز المسار الشهيرة في Nginx مع PHP-FPM. الحارس try_files غير قابل للتفاوض في الإنتاج.
الإحالة إلى خلفية التطبيق عبر proxy_pass
تتحدث خلفيات Node.js وPython (Gunicorn/uvicorn) وRuby (Puma) وGo وJava بروتوكول HTTP مباشرةً. يُحيل Nginx إليها باستخدام proxy_pass — موجه أبسط ومستوى أعلى من fastcgi_pass.
TRUSTED_PROXIES=* أو اذكر عناوين IP لـ Nginx.
المسار الكامل للطلب — تمثيل بصري
يُظهر الرسم البياني التالي المسارين جنبًا إلى جنب: طلب أصل ثابت لا يغادر Nginx إطلاقًا، وطلب ديناميكي يمر عبر FPM أو خلفية بروكسي قبل وصول الاستجابة إلى المتصفح.
أشيع حالات الفشل وكيفية تشخيصها
- 502 Bad Gateway — وصل Nginx إلى PHP-FPM أو خلفية التطبيق لكن الخلفية رفضت الاتصال أو تعطلت. تحقق بـ
sudo systemctl status php8.3-fpmوsudo tail -f /var/log/php8.3-fpm.log. أشيع الأسباب: مجموعة FPM مستنفدة (كل العمال مشغولون) أو مسار الـ socket في إعداداتك لا يطابق المسار الفعلي في/etc/php/8.3/fpm/pool.d/www.conf. - 504 Gateway Timeout — الخلفية حية لكنها تستغرق وقتًا طويلًا. انتهت مهلة
proxy_read_timeoutأوfastcgi_read_timeout. إما أن الطلب بطيء بطبيعته (استعلام DB طويل، استدعاء API خارجي) أو الخلفية في حالة توقف. تحقق من سجلات الاستعلام البطيء وتتبع التطبيق أولًا. - 404 على ملفات PHP — غالبًا عدم تطابق
root. شغّلnginx -T | grep rootوقارن المسار الكامل بما على القرص فعلًا عبرls -la. - تغييرات الملفات الثابتة غير ظاهرة — المتصفح أو CDN يخزّن النسخة القديمة. إن لم تكن الأصول مُبصومة، غيّر
expiresإلىoffأو1hأثناء التطوير.
curl -I http://localhost/path/to/file من الخادم نفسه يتجاوز طبقات DNS وCDN ويُظهر بالضبط ما يُعيده Nginx. أضف -v للرؤوس الكاملة. اجمعه مع sudo nginx -t للتحقق من الإعداد قبل إعادة التشغيل ومع sudo tail -f /var/log/nginx/error.log لمراقبة الأخطاء مباشرةً.