الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
How To Make It

اعمل Rate Limiting لحماية الـ API بتاعك بـ Nginx في 8 خطوات

متوسط28 يوليو 20266 دقائق قراءة
اعمل Rate Limiting لحماية الـ API بتاعك بـ Nginx في 8 خطوات

هذا المقال يتطلب مستوى: متوسط. لازم تكون مرتاح مع سطر أوامر لينكس وعندك فكرة أساسية عن Nginx كـ reverse proxy. لو مبتدئ خالص، المثال في الأول هيوصّلك الفكرة قبل التفاصيل التقنية.

في 8 خطوات، هتحطّ حدًّا على عدد الطلبات اللي أي IP يقدر يبعتها لمسار حسّاس زي تسجيل الدخول. النتيجة العملية: هجوم تخمين كلمات السر اللي بيبعت 8000 طلب في الدقيقة هيتقصّ لـ 10 طلبات في الثانية بس، وضغط قاعدة بياناتك بينزل من 95% لأقل من 20% من غير ما تلمس كود التطبيق.

المشكلة باختصار

لو عندك endpoint زي /api/login مفتوح بلا حد، أي حد يقدر يقصفه بآلاف الطلبات في الثانية. ده بيعمل حاجتين وحشتين. الأولى: هجوم brute force بيجرّب كلمات سر كتير بسرعة. الثانية: طلب واحد تقيل مضروب آلاف المرات بيشيل الـ CPU والـ DB لـ 100% ويوقّع الخدمة لكل المستخدمين. الحل مش سيرفر أقوى، الحل بوابة بتنظّم التدفق قبل ما يوصل لتطبيقك.

الفكرة الأول بمثال، وبعدين علميًا

تخيّل ملهى فيه بوّاب على الباب. الصالة تستحمل ناس بمعدل ثابت، مثلًا واحد كل ثانية. لو جِه 50 شخص مرة واحدة، البوّاب مبيزنقهمش كلهم جوه. بيدخّل واحد كل ثانية، وبيخلّي عدد محدود يستنى في طابور صغير جنب الباب. اللي زاد عن الطابور بيترفض ويمشي. ده بالظبط اللي Nginx بيعمله بطلبات الـ HTTP.

علميًا، Nginx بينفّذ خوارزمية اسمها الدلو المسرّب (Leaky Bucket). تخيّل دلو له تقب صغير تحت. الطلبات بتصبّ فيه من فوق، والتقب بيسرّبها لتطبيقك بمعدل ثابت. حجم الدلو هو الـ burst. لو الطلبات جت أسرع من التسريب، الدلو بيمتلي؛ واللي يجي بعد ما يفيض بيترفض فورًا بكود 503 افتراضيًا أو 429 بعد ما نظبّطه. ركّز على الفرق: rate بيحدّد سرعة التسريب، وburst بيحدّد قد إيه تسمح بدفعة مفاجئة قبل الرفض.

الخطوات الثمانية

  1. قِس خط الأساس الأول. قبل ما تحطّ أي حد، اعرف المعدل الطبيعي لمستخدميك. بُصّ في access log واحسب أعلى معدل شرعي لكل IP. لو مستخدم عادي بيعمل 2 إلى 3 طلبات في الثانية وقت الذروة، حدّ 10r/s آمن وبيسيب مساحة.
  2. عرّف منطقة التتبّع في بلوك http. دي بتحجز ذاكرة مشتركة تتابع فيها معدل كل مفتاح (هنا الـ IP).
  3. طبّق الحد على المسار الحسّاس جوه بلوك location بتاع تسجيل الدخول أو الـ API.
  4. اضبط burst وnodelay عشان تسمح بدفعات قصيرة طبيعية من غير ما تعاقب المستخدم الشرعي.
  5. غيّر كود الرفض لـ 429 بدل 503 الافتراضي، لأن 429 هو الكود القياسي الصحيح لـ "طلبات كتير أوي".
  6. اعمل استثناء للـ IPs الموثوقة زي سيرفرات المراقبة أو بوابة الدفع، عشان متتحدّش بالغلط.
  7. تحقّق من الإعداد وأعد التحميل بأمان. nginx -t بيمنعك من كسر السيرفر بكونفيج غلط.
  8. اختبر بحمل حقيقي وراقب اللوج عشان تتأكد إن اللي بيترفض هو الزيادة بس.

الكونفيج الكامل (قابل للنسخ)

الملف ده بيغطّي الخطوات من 2 لـ 6. حطّه في /etc/nginx/nginx.conf أو ملف داخل conf.d.

# --- جوه بلوك http ---
# منطقة بـ 10 ميجا تكفي تتبّع حوالي 160 ألف IP
# الحد: 10 طلبات في الثانية لكل IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

# كود الرفض الصحيح لتجاوز الحد
limit_req_status 429;

# استثناء الـ IPs الموثوقة: بنحيّد المفتاح لو الـ IP في القائمة
geo $limit_key {
    default         $binary_remote_addr;
    10.0.0.5        "";   # سيرفر المراقبة
    52.20.13.44     "";   # بوابة الدفع
}

server {
    listen 80;
    server_name api.example.com;

    location /api/login {
        # burst=20: يسمح بدفعة 20 طلب فوق المعدل
        # nodelay: يخدمها فورًا بدل ما يأخّرها في طابور
        limit_req zone=api_limit burst=20 nodelay;

        proxy_pass http://127.0.0.1:3000;
    }
}
شاشة طرفية تعرض كود إعداد خادم لتحديد معدل الطلبات بتوجيهة limit_req

الخطوة 7 و8: التطبيق والاختبار

اتأكد الأول إن الكونفيج سليم قبل ما تعيد التحميل. الأمر ده بيفحص من غير ما يوقّع السيرفر:

Bash
# فحص الكونفيج
sudo nginx -t

# إعادة تحميل بلا قطع اتصالات (graceful)
sudo systemctl reload nginx

بعد كده، اقصف الـ endpoint بحمل حقيقي بأداة زي hey وشوف كام طلب عدّى وكام اترفض:

Bash
# 2000 طلب، 50 في نفس الوقت
hey -n 2000 -c 50 http://api.example.com/api/login

# النتيجة المتوقعة: جزء بيرجع 200، والباقي 429
# [200] 220 responses
# [429] 1780 responses

التحقق من أنه يعمل فعلاً

افتح لوج Nginx ودوّر على سطر الرفض. لو لقيته، يبقى الحد شغّال:

Bash
grep "limiting requests" /var/log/nginx/error.log
# limiting requests, excess: 20.000 by zone "api_limit", client: 203.0.113.9

الأرقام: قبل وبعد

الأرقام دي من سيناريو واقعي لـ API عربي عليه حوالي 40 ألف مستخدم يومي، اتعرّض لهجوم تخمين على /api/login. الافتراض إن السيرفر خلفه Node.js وقاعدة PostgreSQL:

  • الطلبات الواصلة للتطبيق: من 8000 طلب/دقيقة لـ ~600 طلب/دقيقة (10r/s فعليًا).
  • استهلاك CPU على قاعدة البيانات: من 95% لـ أقل من 20%.
  • زمن الاستجابة P95 للمستخدم الشرعي: من 1900 مللي ثانية لـ ~120 مللي ثانية.
  • التكلفة: صفر. مفيش هاردوير جديد ولا تعديل كود. دقيقة إعداد وإعادة تحميل.

الأرقام دي تقديرية وبتختلف حسب حجم الطلب وقوة السيرفر، لكن ترتيب الحجم ثابت: بتقطع معظم الحمل الخبيث قبل ما يلمس تطبيقك.

الـ trade-offs وما يجب الانتباه له

كل توصية ليها ثمن. خلّي بالك من التلات نقط دي:

  • المفتاح $binary_remote_addr بيتحسب لكل IP. لو مستخدمينك ورا NAT أو بروكسي شركة، هيطلعوا بنفس الـ IP وهتحدّهم كأنهم شخص واحد. بتكسب حماية، بتخسر دقة لمّا الناس بيشاركوا IP. الحل: استخدم $http_x_forwarded_for بحذر، وبس لو انت متأكد إن البروكسي بتاعك موثوق.
  • nodelay بيخدم الدفعة فورًا بدل ما يوزّعها. بتكسب زمن استجابة أحسن للمستخدم الطبيعي، بتخسر التنعيم اللي بيحمي سيرفرات upstream ضعيفة. لو الـ backend بتاعك هش، شيل nodelay وسيب الطابور يوزّع.
  • الحد على مستوى instance واحد. لو عندك أكتر من سيرفر Nginx ورا load balancer، كل واحد بيعدّ لوحده. يعني الحد الفعلي بيتضاعف بعدد السيرفرات. للحد الموزّع الحقيقي محتاج طبقة زي Redis أو حل على مستوى الـ API gateway.

متى لا تستخدم هذه الطريقة

Rate limiting على Nginx مش الحل الصح في كل حالة. متستخدمهوش لو محتاج حدود لكل مستخدم مسجّل (per-user) مش لكل IP، لأن Nginx مبيعرفش هوية المستخدم؛ ده شغل التطبيق أو API gateway زي Kong. كمان لو بتتعرّض لهجوم DDoS موزّع من آلاف الـ IPs، الحد لكل IP مش هيكفي، وهتحتاج طبقة حماية على مستوى الشبكة زي Cloudflare قبل ما توصل لـ Nginx أصلًا. وأخيرًا، لو الترافيك عندك قليل ومنتظم، الحد ممكن يعقّد حياتك بلا داعي.

الخطوة التالية

افتح كونفيج Nginx بتاعك دلوقتي، وحدّد endpoint واحد حسّاس (تسجيل الدخول أو reset password)، وطبّق عليه limit_req zone=api_limit burst=20 nodelay; بحد 10r/s. بعدين اقصفه بـ hey -n 2000 -c 50 وشوف نسبة الـ 429. لو ظهرت، يبقى بوّابك بقى شغّال.

المصادر

  • توثيق Nginx الرسمي — وحدة ngx_http_limit_req_module (توجيهات limit_req_zone وlimit_req وburst وnodelay): nginx.org/en/docs/http/ngx_http_limit_req_module.html
  • مدوّنة Nginx الرسمية — "Rate Limiting with NGINX" (شرح خوارزمية الدلو المسرّب وburst): blog.nginx.org/blog/rate-limiting-nginx
  • MDN Web Docs — كود الحالة 429 Too Many Requests: developer.mozilla.org/en-US/docs/Web/HTTP/Status/429
  • Cloudflare Learning Center — What is rate limiting: cloudflare.com/learning/bots/what-is-rate-limiting
  • أداة اختبار الحمل hey: github.com/rakyll/hey

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة