برای محدود کردن درخواست در Nginx از دو ماژول داخلی استفاده میکنید: limit_req تعداد درخواست در بازه زمانی را محدود میکند و limit_conn تعداد اتصال همزمان را. با چند خط تنظیم میتوانید جلوی حدس رمز روی wp-login.php، اسکریپتهای پرتکرار و فشار ناگهانی روی سایت را بگیرید و بهجای قطعی کامل، به درخواستهای اضافه پاسخ 429 بدهید.
این روش جایگزین فایروال نیست و پوشش مکمل آن است. برای مسدود کردن دائمی آدرسهای مهاجم، نصب و تنظیم Fail2ban را هم ببینید. اگر Nginx ندارید، ابتدا نصب Nginx روی اوبونتو را انجام دهید.
limit_req: چطور کار میکند؟
Nginx با الگوریتم «سطل نشتی» (leaky bucket) درخواستها را با نرخ ثابت پردازش میکند. دو تنظیم لازم دارید:
limit_req_zoneدر بخشhttpکه حافظه و نرخ را تعریف میکند.limit_reqدرserverیاlocationکه منطقه را اعمال میکند.
http {
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_status 429;
}معنی:
$binary_remote_addr: کلید محدودیت، یعنی آدرس IP کلاینت (فرم فشرده).zone=general:10m: نام منطقه و 10 مگابایت حافظه؛ حدود 160 هزار آدرس را نگه میدارد.rate=10r/s: ده درخواست در ثانیه.5r/mیعنی پنج درخواست در دقیقه.limit_req_status 429: کد پاسخ هنگام رد درخواست (پیشفرض 503 است).
محدود کردن درخواست در Nginx برای ورود وردپرس
صفحه ورود هدف اصلی حدس رمز است:
server {
listen 443 ssl;
server_name example.com;
location = /wp-login.php {
limit_req zone=login burst=3 nodelay;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
limit_req zone=general burst=20 nodelay;
try_files $uri $uri/ /index.php?$args;
}
}مسیر سوکت PHP و نسخه نمونه است. دو گزینه مهم دیگر:
burst=3: اجازه میدهد تا سه درخواست اضافه در صف بیایند، تا ترافیک عادی که کمی تند است رد نشود.nodelay: درخواستهای burst را بدون تأخیر پردازش میکند و فقط بعد از پر شدن آن رد میکند. بدون آن، درخواستها با تأخیر و با همان نرخ پردازش میشوند.
limit_conn: محدود کردن اتصال همزمان
برای جلوگیری از اینکه یک IP تعداد زیادی اتصال همزمان بسازد (مثلاً دانلود موازی یا حمله ساده):
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
}
server {
limit_conn perip 20;
}عدد را متناسب با کاربرد بگذارید. پشت NAT سازمانی، چند کاربر یک IP مشترک دارند و عدد خیلی کم آنها را مسدود میکند.
آدرس واقعی پشت Cloudflare یا پراکسی
اگر سایت پشت Cloudflare یا یک پراکسی است، $remote_addr آدرس آنهاست و همه کاربران یک «IP» دارند. باید آدرس واقعی را با ماژول realip بگیرید:
set_real_ip_from 173.245.48.0/20;
real_ip_header CF-Connecting-IP;فهرست کامل آدرسهای Cloudflare را از سایت رسمی بردارید و همه را بنویسید. بدون این تنظیم، یک مهاجم باعث محدود شدن همه کاربران میشود. راهاندازی Cloudflare در Reverse Proxy چیست هم از دید پراکسی بررسی شده است.
استثنا برای آدرسهای مجاز
برای دفتر یا سرویس پایش که نباید محدود شود، با geo و map کلید را خالی کنید (کلید خالی محدود نمیشود):
geo $limit {
default 1;
203.0.113.0/24 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;آدرس نمونه است. با این روش، آدرسهای لیست مجاز در محدودیت نمیافتند.
آزمایش محدود کردن درخواست در Nginx
بعد از تنظیم، همیشه آزمایش و بارگذاری:
sudo nginx -t
sudo systemctl reload nginxبرای دیدن اثر، از یک ترمینال درخواستهای پشتسرهم بفرستید:
for i in $(seq 1 15); do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/wp-login.php; doneبعد از چند درخواست باید 429 ببینید. در error.log هم پیامهایی مثل limiting requests, excess: 3.5 ثبت میشود. برای خارج نکردن ربات گوگل از محدودیت، نرخ را برای مسیرهای عمومی بالا بگذارید؛ رباتهای معتبر با رد شدن مکرر، خزش را کم میکنند.
نرخ مناسب چقدر است؟
عدد دقیقی برای همه سایتها وجود ندارد، ولی راهنمای معقول:
| مسیر | نرخ پیشنهادی شروع |
|---|---|
صفحه ورود (wp-login.php) | 5 درخواست در دقیقه، burst پایین |
xmlrpc.php | اگر لازم نیست، کاملاً ببندید |
| API عمومی | بر اساس مصرف واقعی، مثلاً 10 درخواست در ثانیه |
| کل سایت | 10 تا 30 درخواست در ثانیه برای هر IP با burst |
بعد از چند روز لاگ را بررسی کنید و ببینید چقدر 429 تولید شده؛ اگر کاربر عادی رد میشود، نرخ را بالا ببرید.
خطاهای رایج
| نشانه | علت و راه حل |
|---|---|
| همه کاربران 429 میگیرند | آدرس واقعی گرفته نمیشود (پشت CDN)؛ realip را تنظیم کنید |
limit_req_zone خطای «not allowed here» | فقط در بخش http مجاز است و داخل server خطا میدهد |
| محدودیت اثر ندارد | منطقه تعریف شده ولی limit_req در location درست قرار نگرفته |
| کاربران عادی رد میشوند | burst کم است یا نرخ پایین |
| حافظه منطقه پر شد | zone را بزرگتر کنید (پیام could not allocate node در لاگ) |
| پاسخ 503 بهجای 429 | limit_req_status 429 تنظیم نشده |
سوالات متداول
آیا این محدودیت جای Fail2ban را میگیرد؟
نه. محدودیت درخواست فشار لحظهای را کم میکند. Fail2ban آدرسهای مهاجم را بر اساس لاگ برای مدت طولانیتری مسدود میکند. مکمل هماند.
آیا رباتهای جستوجو را مسدود میکند؟
اگر نرخ خیلی پایین باشد، بله. نرخ مسیرهای عمومی را بالا بگذارید و فقط مسیرهای حساس (ورود، API) را محدود کنید.
فرق rate و burst چیست؟
rate نرخ دائمی مجاز است. burst تعداد درخواست اضافهای است که برای نوسان کوتاهمدت در صف تحمل میشود.
روی Apache هم میشود؟
Apache برای این کار ماژولهایی مثل mod_evasive یا mod_qos دارد و روش آن فرق میکند.





