nginx -t قبل كده وعارف إن الـ config بيتحط في /etc/nginx/conf.d/، انت في المكان الصح. لو لسه في الأول، فيه مثال البقالة في الجزء التاني هيخلي كل حاجة واضحة.
لو الـ API بتاعك بيرجّع 502 Bad Gateway لمدة 15 دقيقة كل يوم الساعة 9 صباحاً، المشكلة مش دايماً في الـ backend. الموجة بتدخل NGINX، وNGINX بيمررها كلها للتطبيق بدون أي حد، والـ workers بتمتلئ، والمستخدمين الحقيقيين بيشوفوا 502. الحل في 10 سطور config على طبقة NGINX قبل ما الـ request يلمس تطبيقك أصلاً.
NGINX Rate Limiting: حماية الـ API بطبقة واحدة قبل التطبيق
المشكلة باختصار
NGINX بشكل افتراضي بيمرر كل request للـ backend بدون أي حد. لو واحد كتب bot ضرب على /api/login بـ 10K request/ثانية، الـ Node.js workers بتاعتك أو الـ PHP-FPM pool هيتشغّلوا في الـ requests الخبيثة دي، والمستخدمين الحقيقيين هيشوفوا 502. NGINX بيرفض الـ request في 0.3ms بدل ما تطبيقك ياخد 200ms + database connection لكل واحد.
مثال للمبتدئ: محل البقالة فيه كاشير واحد
تخيّل محل بقالة فيه كاشير واحد بيخدم 5 عملاء في الدقيقة. لو دخل المحل 50 عميل في نفس الدقيقة، الكاشير هيبطّأ، الطابور هيتخنق، والمحل هيقفل لأنه امتلأ. الحل: حارس على الباب بيقول "ادخلوا 5 في الدقيقة بس، الباقي يستنوا في طابور احتياطي بيسع 10 ناس فقط، اللي يجي بعدهم نقوله ارجع بعدين".
NGINX limit_req هو الحارس ده بالظبط:
- rate = الكاشير (مثلاً 5 طلبات/ثانية).
- burst = الطابور الاحتياطي (مثلاً 10 طلبات إضافية مؤقتة).
- الـ request اللي بعدهم بيتقطع بـ 503 أو 429.
التعريف الدقيق: خوارزمية Leaky Bucket
limit_req مبني على Leaky Bucket. كل client (مُعرَّف بـ IP افتراضياً) عنده "دلو" بحجم محدد، والـ requests بتدخل فيه. الدلو بيتسرّب بمعدل ثابت (مثلاً 10 req/sec). لو الـ request دخلت والدلو ممتلي، الـ request بترفض. الفرق بين limit_req و limit_conn: الأول بيحدّ معدل الطلبات في الزمن، التاني بيحدّ عدد الاتصالات المتزامنة. الاتنين مفيدين، لكن limit_req أهم لمنع الـ floods.
الـ config الكامل (قابل للنسخ)
# /etc/nginx/conf.d/limit.conf
http {
# دلو 10MB يحفظ ~160K IP فريد
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# دلو منفصل للـ login (أصغر، أبطأ)
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=2r/s;
server {
listen 443 ssl http2;
server_name api.example.com;
# endpoint عادي: 10 req/sec + burst 20
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
# endpoint حساس: 2 req/sec + burst 5
location /api/login {
limit_req zone=login_limit burst=5 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
}
}