背景服务器上有个公开的 dashboard虽然不对外宣传但日志里经常看到同一个 IP 一秒钟请求几十次某个爬虫把整站扫了一遍偶尔有恶意请求把 CPU 拉满fail2ban 能封 IP但它是事后——等攻击发生了才封。想做到事前限流让恶意请求根本打不进来。解决Nginx 限流有三个武器武器作用适用场景limit_req限制请求速率防 CC、防爬虫limit_conn限制并发连接数防慢速攻击limit_rate限制响应速度防大文件盗刷一、limit_req限制请求速率第一步在 http 块定义限流区# 按 IP 限流10MB 内存每秒 10 个请求 limit_req_zone $binary_remote_addr zonereq_per_ip:10m rate10r/s;参数说明参数含义$binary_remote_addr按客户端 IP 分组比$remote_addr省内存zonereq_per_ip:10m区域名 10MB 内存约存 16 万个 IP 状态rate10r/s每秒 10 个请求第二步在 server 或 location 里应用location / { limit_req zonereq_per_ip burst20 nodelay; # ... }参数解释参数含义burst20允许突发 20 个请求排队nodelay突发请求立即处理不延迟效果正常用户秒开无感CC 攻击超过 10r/s 后多出来的请求被延迟或拒绝返回 503第三步自定义拒绝状态码可选limit_req_status 429;默认是 503改成 429Too Many Requests更语义化。二、limit_conn限制并发连接数第一步定义连接区limit_conn_zone $binary_remote_addr zoneconn_per_ip:10m;第二步应用location / { limit_conn conn_per_ip 20; # 每个 IP 最多 20 个并发连接 # ... }三、limit_rate限制响应速度location /download/ { limit_rate 1m; # 每个连接限速 1MB/s limit_rate_after 10m; # 前 10MB 不限速 }用途防大文件被疯狂下载。四、完整配置# /etc/nginx/nginx.conf 的 http 块里 limit_req_zone $binary_remote_addr zonereq_per_ip:10m rate10r/s;limit_conn_zone $binary_remote_addr zoneconn_per_ip:10m;limit_req_status 429;# server 块里 server{listen 8443 ssl;# ... location /{limit_req zonereq_per_ip burst20 nodelay;limit_conn conn_per_ip 20;proxy_passhttp://backend_cluster;}# 静态文件放宽一点 location /static/{limit_req zonereq_per_ip burst50 nodelay;# ...}# API 收紧一点 location /api/{limit_req zonereq_per_ip burst5 nodelay;# ...}}关键原则静态资源松API 紧。因为加载一个页面可能同时请求几十个静态文件JS、CSS、图片API 每个请求都是计算不该被刷验证效果测试限流生效# 用 ab 或 wrk 打 100 个并发请求 ab -n 100 -c 10 https://example.com:8443/ # 看结果 Complete requests: 100 Non-2xx responses: 40 ← 40 个被限流了看 Nginx 日志sudotail-f/var/log/nginx/access.log|grep429期望能看到部分请求返回 429。看限流状态Nginx 的 stub_status 模块能看到当前连接数location /nginx-status { stub_status; allow 127.0.0.1; deny all; }curl http://127.0.0.1/nginx-status Active connections: 2 server accepts handled requests 1000 1000 5000 Reading: 0 Writing: 1 Waiting: 1实际效果指标改造前改造后单 IP 峰值请求200/s10/s超出被限CPU 峰值90%40%正常用户响应正常正常CC 攻击效果有效基本无效三个坑坑 1rate 和 burst 配得太紧rate1r/s burst0后果页面加载 10 个静态文件超过 1 个就限。正常用户都打不开。建议起步值场景rateburst个人网站10r/s20API5r/s10静态资源50r/s100调优方法先配宽松一点观察日志看正常用户的峰值是多少再往下压。坑 2limit_req_zone 内存不够10m 大约存 16 万个 IP 状态。如果攻击者用大量代理 IP比如僵尸网络状态表满了之后新 IP 无法被限流。监控方法# 在 http 块 limit_req_zone $binary_remote_addr zonereq_per_ip:10m rate10r/s;Nginx 会在日志里警告limiting requests, excess: 0.500 by zone req_per_ip如果经常看到说明内存不够或真的被打。建议个人服务器 10m 够用大流量网站加到 50m。坑 3CDN / 反代后$binary_remote_addr 是 CDN 的 IP问题如果前面挂了 Cloudflare / CDNNginx 拿到的 $remote_addr 是 CDN 的 IP不是真实用户 IP。结果所有用户共用一个限流额度 → 正常用户被误伤。修复配置 real_ip 模块从 X-Forwarded-For 提取真实 IPset_real_ip_from 173.245.48.0/20; # Cloudflare 的 IP 段 set_real_ip_from 103.21.244.0/22; real_ip_header CF-Connecting-IP;用 $binary_remote_addr 时它已经是被 real_ip 替换后的真实 IP没有 CDN 就不需要这一条。生活小插曲我的个人博客搭建好了也备好案了链接直达 点击这里