如何通过Nginx(Ubuntu环境配置)拦截网站高频请求及短时间多发请求IP
Alright, let's tackle these two Nginx request limiting questions head-on—this is a super common setup for protecting your site from bots, scrapers, or accidental traffic spikes, so I'll break it down step by step for Ubuntu systems.
核心原理:Nginx的limit_req模块
Nginx自带的ngx_http_limit_req_module就是干这个的核心工具,它的逻辑很简单:
- 先创建一块共享内存区域,用来追踪每个客户端IP的请求频率
- 给网站的指定区域套上速率限制规则,超过阈值的请求直接拦截或延迟处理
首先先确认你的Nginx安装了这个模块——Ubuntu默认的Nginx包一般都带,但还是检查一下更稳妥:
nginx -V 2>&1 | grep -- '--with-http_limit_req_module'
如果没看到输出,就装完整版本的Nginx:
sudo apt update && sudo apt install nginx-full
Ubuntu系统上的具体配置步骤
1. 定义速率限制区域(编辑/etc/nginx/nginx.conf)
打开主配置文件,在http块里添加这段配置,用来创建存储请求数据的共享内存:
http { # ... 保留原有配置 ... # 创建名为req_limit的内存区域,分配10MB空间(大概能存16万个IP的追踪数据) # 用客户端IP的二进制格式来节省内存(比字符串格式省很多) # 限制基线速率为每分钟60次请求(可根据你的需求调整) limit_req_zone $binary_remote_addr zone=req_limit:10m rate=60r/m; }
zone=req_limit:10m: 给内存区域命名并分配空间,10MB足够中小站点使用$binary_remote_addr: 用二进制存储IP,比字符串格式的$remote_addr省内存,高流量场景必备rate=60r/m: 设置基线速率,r/m是每分钟请求数,也可以用r/s表示每秒(比如10r/s)
2. 给站点/路径应用限制规则(编辑站点配置,比如/etc/nginx/sites-available/your-site.conf)
把限制规则加到你要保护的server或location块里:
server { listen 80; server_name your-domain.com; # 给整个站点应用限制 location / { # 调用我们刚才定义的req_limit区域 # burst=20允许20次突发请求(应对临时流量峰值) # nodelay表示超过突发阈值的请求直接返回503,不排队等待 limit_req zone=req_limit burst=20 nodelay; # ... 保留你原有的站点配置(root、index等) ... root /var/www/your-domain; index index.html; } # 可选:给API接口设置更严格的限制 location /api/ { limit_req zone=req_limit burst=10 nodelay; # ... API相关配置 ... } }
burst=20: 允许客户端在基线速率外,额外发送20次请求,应对临时的流量波动nodelay: 超过突发阈值的请求直接返回503,而不是让用户等待排队,适合对响应速度敏感的场景
3. 自定义错误页面(可选)
如果不想用默认的503页面,就给服务器块加这段配置:
error_page 503 /custom-503.html; location = /custom-503.html { root /var/www/your-domain; internal; # 只允许Nginx内部跳转访问,不让用户直接访问 }
然后在站点根目录创建custom-503.html,写你自己的提示内容就行。
4. 测试配置并重启Nginx
修改完配置后一定要先检查语法错误:
sudo nginx -t
看到test is successful的提示后,重启Nginx生效:
sudo systemctl restart nginx
进阶优化技巧
给信任IP开白名单
如果想让自己的办公IP或服务器IP不受限制,可以用geo模块实现白名单。在nginx.conf的http块里加:
geo $limit_whitelist { default 1; 192.168.1.100 0; # 你的信任IP 10.0.0.0/8 0; # 整个内网网段 } # 保持之前的limit_req_zone配置不变 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=60r/m;
然后修改location块,只对白名单外的IP应用限制:
location / { if ($limit_whitelist = 1) { limit_req zone=req_limit burst=20 nodelay; } # ... 原有配置 ... }
记录被拦截的请求
如果想追踪哪些请求被拦截了,可以加个自定义日志格式。在nginx.conf的http块里:
http { log_format limit_log '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$limit_status"'; }
然后在站点配置里用这个日志格式:
server { # ... 原有配置 ... access_log /var/log/nginx/your-domain-access.log limit_log; }
日志里的$limit_status字段会显示REJECTED,标记被拦截的请求。
内容的提问来源于stack exchange,提问作者Akash lal

