Nginx 限流防刷完全指南從原理到生產(chǎn)實(shí)戰(zhàn)指南
一、核心原理
Nginx 提供兩個核心模塊實(shí)現(xiàn)限流,各司其職:
| 模塊 | 功能 | 算法/機(jī)制 | 適用場景 |
|---|---|---|---|
ngx_http_limit_req_module | 限制單個 IP 在單位時間內(nèi)的請求數(shù)量 | 漏桶算法 | 防刷接口、控制 QPS |
ngx_http_limit_conn_module | 限制單個 IP 同時建立的連接數(shù)量 | 連接計數(shù) | 防 CC 攻擊、防連接耗盡 |
漏桶算法:以固定速率處理請求,超出速率的請求排隊(duì)或被拒絕。burst 定義桶容量,nodelay 決定是否延遲處理。
二、環(huán)境準(zhǔn)備
系統(tǒng)要求:Ubuntu 20.04 / CentOS 7+,Nginx ≥ 1.1.8(當(dāng)前穩(wěn)定版均支持)。
# Ubuntu sudo apt update && sudo apt install nginx -y # CentOS sudo yum install epel-release -y && sudo yum install nginx -y
確認(rèn)模塊已編譯:
nginx -V 2>&1 | grep -o with-http_limit_req_module nginx -V 2>&1 | grep -o with-http_limit_conn_module
三、基礎(chǔ)配置:限制單 IP 請求速率
3.1 定義限流區(qū)域(http 塊)
http {
# 按客戶端IP限流,10MB共享內(nèi)存(約存16萬IP),每秒10個請求
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# 登錄接口專用:更嚴(yán)格的限制
limit_req_zone $binary_remote_addr zone=login_limit:5m rate=2r/s;
# 并發(fā)連接限制
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}為什么用
$binary_remote_addr而非$remote_addr? 二進(jìn)制格式更省內(nèi)存,推薦生產(chǎn)環(huán)境使用。
3.2 應(yīng)用限流規(guī)則(server/location 塊)
server {
listen 80;
server_name api.example.com;
location /api/ {
# 應(yīng)用限流:允許突發(fā)20個請求,nodelay立即處理突發(fā),超出部分直接拒絕
limit_req zone=api_limit burst=20 nodelay;
# 自定義限流返回狀態(tài)碼(429比默認(rèn)503更符合語義)
limit_req_status 429;
proxy_pass http://backend_server;
}
location /api/login {
# 登錄接口使用更嚴(yán)格的限流
limit_req zone=login_limit burst=5 nodelay;
limit_req_status 429;
proxy_pass http://auth_service;
}
}參數(shù)深度解析:
rate=10r/s:這是長期的平均速率,也可寫30r/m(每分鐘30次)burst=20:當(dāng)請求瞬間超過 10r/s 時,多出來的請求會先進(jìn)入“突發(fā)桶”排隊(duì)。nodelay:加上這個參數(shù),突發(fā)桶里的 20 個請求會立即被處理,而不是按每秒 10 個的速度排隊(duì)。如果不加nodelay,請求會被延遲處理,適合對實(shí)時性要求不高的場景。
四、組合防護(hù):速率 + 連接雙限制
生產(chǎn)環(huán)境推薦同時啟用雙重保護(hù):
http {
# 速率限制區(qū)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=50r/s;
# 連接數(shù)限制區(qū)
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
location /api/ {
proxy_pass http://backend_server;
# 速率限制:每秒50個,允許突發(fā)100個
limit_req zone=api_limit burst=100 nodelay;
# 連接數(shù)限制:單個IP最多同時保持50個連接
limit_conn conn_limit 50;
limit_conn_status 429;
}
}
}五、精細(xì)化限流策略
5.1 按接口路徑限流(防掃描)
防止掃描器遍歷 API,對每個 URI 單獨(dú)計數(shù):
http {
# $uri 不包含查詢參數(shù),如需區(qū)分參數(shù)用 $request_uri
limit_req_zone $uri zone=per_uri:10m rate=10r/s;
}
server {
location / {
limit_req zone=per_uri burst=20 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
}5.2 動態(tài)分級限流(VIP用戶)
通過 map 實(shí)現(xiàn)不同用戶等級的差異化限流:
http {
# 從請求頭獲取用戶等級(需后端傳遞)
map $http_x_user_level $rate_limit {
"vip" "100r/s";
"normal" "10r/s";
default "2r/s";
}
limit_req_zone $binary_remote_addr zone=dynamic:10m rate=$rate_limit;
server {
location /api/ {
limit_req zone=dynamic burst=5 nodelay;
proxy_pass http://backend;
}
}
}注:
rate使用變量需 Nginx 1.15.10+。
5.3 下載限速 + 并發(fā)限制
location /download/ {
limit_conn conn_limit 2; # 單IP最多2個并發(fā)下載
limit_rate 500k; # 單連接限速500KB/s
alias /data/files/;
}5.4針對敏感接口
登錄和驗(yàn)證碼接口是暴力破解的重災(zāi)區(qū),需要設(shè)置更嚴(yán)格的規(guī)則:
http {
# 專門為登錄接口定義一個更嚴(yán)格的限流區(qū):每秒僅允許 2 次請求
limit_req_zone $binary_remote_addr zone=login_limit:5m rate=2r/s;
server {
# 普通接口
location /api/ {
limit_req zone=api_limit burst=50 nodelay;
proxy_pass http://backend_server;
}
# 登錄接口(單獨(dú)配置)
location /api/login {
limit_req zone=login_limit burst=5 nodelay;
limit_req_status 429;
proxy_pass http://backend_server;
}
}
}六、白名單與動態(tài)控制
6.1 白名單配置(geo + map 技巧)
Nginx 的 limit_req 不能直接通過 if 開關(guān),需用 zone 切換實(shí)現(xiàn)"跳過限制":
http {
# 定義白名單
geo $whitelist {
default 0;
203.0.113.0/24 1; # 公司出口IP段
192.168.1.100 1;
}
# 正常限流區(qū)
limit_req_zone $binary_remote_addr zone=global:10m rate=20r/s;
# 虛擬高速區(qū)(白名單IP使用,實(shí)際不限流)
limit_req_zone $binary_remote_addr zone=dummy:1m rate=10000r/s;
# 根據(jù)白名單動態(tài)選擇zone
map $whitelist $limit_zone {
1 "dummy";
0 "global";
}
# 登錄專用區(qū)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
map $whitelist $login_zone {
1 "dummy";
0 "login";
}
# 并發(fā)限制
limit_conn_zone $binary_remote_addr zone=connip:10m;
# 日志格式增加限流信息
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" limit_req_status=$limit_req_status';
server {
listen 80;
server_name api.example.com;
access_log /var/log/nginx/api_access.log main;
limit_req_status 429;
limit_conn_status 429;
# 全局接口
location / {
limit_req zone=$limit_zone burst=30 nodelay;
limit_conn connip 20;
proxy_pass http://backend;
}
# 登錄接口
location /api/login {
limit_req zone=$login_zone burst=3 nodelay;
proxy_pass http://auth;
}
# 下載接口
location /download/ {
limit_conn connip 2;
limit_rate 500k;
alias /data/downloads/;
}
}
}七、CDN / 反向代理場景
如果 Nginx 前有 CDN 或 NAT,需獲取真實(shí)客戶端 IP:
# 配置真實(shí)IP來源 set_real_ip_from 10.0.0.0/8; # CDN節(jié)點(diǎn)網(wǎng)段 set_real_ip_from 172.16.0.0/12; real_ip_header X-Forwarded-For; # 使用真實(shí)IP限流 limit_req_zone $http_x_forwarded_for zone=cdn_limit:10m rate=20r/s;
八、友好的限流提示
自定義 429 錯誤頁面,返回 JSON:
server {
# 自定義限流錯誤
error_page 429 = @rate_limited;
location @rate_limited {
default_type application/json;
return 429 '{"code": 429, "msg": "請求過于頻繁,請稍后再試"}';
}
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
}九、測試與驗(yàn)證
9.1 ApacheBench (ab)
# 安裝 sudo apt install apache2-utils # Ubuntu sudo yum install httpd-tools # CentOS # 發(fā)送100個請求,并發(fā)10個 ab -n 100 -c 10 http://api.example.com/api/test
9.2 curl 循環(huán)測試
for i in {1..100}; do
http_code=$(curl -s -o /dev/null -w "%{http_code}" http://api.example.com/api/test)
echo "Request $i: $http_code"
done9.3 日志排查
# 實(shí)時查看限流日志 tail -f /var/log/nginx/error.log | grep "limiting requests" # 統(tǒng)計429狀態(tài)碼數(shù)量 grep " 429 " /var/log/nginx/access.log | wc -l # 查看限流狀態(tài)(若配置了日志格式) tail -f /var/log/nginx/api_access.log
十、進(jìn)階優(yōu)化
10.1 調(diào)整日志級別
limit_req_log_level error; # 默認(rèn)warn,可選info/notice/warn/error limit_conn_log_level error;
10.2 結(jié)合 Fail2ban 自動封禁
配置 Fail2ban 監(jiān)控 429 日志,超限直接 iptables 封禁:
# /etc/fail2ban/jail.local [nginx-req-limit] enabled = true filter = nginx-req-limit action = iptables-multiport[name=ReqLimit, port="http,https"] logpath = /var/log/nginx/api_access.log maxretry = 10 findtime = 60 bantime = 600
# /etc/fail2ban/filter.d/nginx-req-limit.conf [Definition] failregex = ^<HOST> -.* 429 ignoreregex =
10.3 平滑重載配置
sudo nginx -t && sudo systemctl reload nginx
十一、完整生產(chǎn)配置示例
http {
# ========== Zone 定義 ==========
limit_req_zone $binary_remote_addr zone=global:20m rate=20r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=dummy:1m rate=10000r/s;
limit_conn_zone $binary_remote_addr zone=connip:10m;
# ========== 白名單 ==========
geo $whitelist {
default 0;
203.0.113.0/24 1;
}
map $whitelist $limit_zone {
1 "dummy";
0 "global";
}
map $whitelist $login_zone {
1 "dummy";
0 "login";
}
# ========== 日志 ==========
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" limit_req_status=$limit_req_status';
server {
listen 80;
server_name api.example.com;
access_log /var/log/nginx/api_access.log main;
limit_req_status 429;
limit_conn_status 429;
# 全局API
location /api/ {
limit_req zone=$limit_zone burst=30 nodelay;
limit_conn connip 20;
proxy_pass http://backend;
}
# 登錄(更嚴(yán)格)
location /api/login {
limit_req zone=$login_zone burst=3 nodelay;
proxy_pass http://auth;
}
# 下載
location /download/ {
limit_conn connip 2;
limit_rate 500k;
alias /data/downloads/;
}
# 限流提示
error_page 429 = @rate_limited;
location @rate_limited {
default_type application/json;
return 429 '{"code":429,"msg":"請求過于頻繁,請稍后再試"}';
}
}
}十二、關(guān)鍵注意事項(xiàng)
| 要點(diǎn) | 說明 |
|---|---|
| 共享內(nèi)存大小 | 10MB 約存16萬IP,日活大需調(diào)大 |
| burst + nodelay | 不加 nodelay 會延遲排隊(duì),加則直接丟棄超限請求 |
| CDN/代理 | 必須配置 real_ip_header 獲取真實(shí)IP,否則誤傷 |
| 閾值調(diào)優(yōu) | 根據(jù)后端實(shí)際抗壓能力和正常用戶習(xí)慣動態(tài)調(diào)整 |
| 限流非目的 | 本質(zhì)是為后端爭取恢復(fù)空間,需配合監(jiān)控和自動封禁 |
通過合理組合 limit_req 和 limit_conn,配合白名單、分級限流、友好提示和 Fail2ban 聯(lián)動,可以為 API 構(gòu)建一道低成本、高效率的防護(hù)墻。
到此這篇關(guān)于Nginx 限流防刷完全指南從原理到生產(chǎn)實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)nginx 限流防刷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nginx服務(wù)器配置https安全協(xié)議的實(shí)現(xiàn)
HTTP是互聯(lián)網(wǎng)中最常用的協(xié)議,用于從服務(wù)器傳輸超文本到瀏覽器,HTTPS是HTTP的安全版本,本文就來介紹一下Nginx服務(wù)器配置https安全協(xié)議的實(shí)現(xiàn),感興趣的可以了解一下2024-09-09
nginx rewrite 偽靜態(tài)配置參數(shù)和使用例子
nginx下偽靜態(tài)配置參數(shù)詳細(xì)說明,使用nginx的朋友,nginx rewrite 偽靜態(tài)配置參數(shù)和使用例子 附正則使用說明2010-07-07
Nginx實(shí)現(xiàn)動態(tài)路由映射的完整示例
在Nginx中實(shí)現(xiàn)動態(tài)路徑映射,通常使用正則表達(dá)式location+捕獲組+ alias或root來完成,下面給大家介紹Nginx實(shí)現(xiàn)動態(tài)路由映射的完整示例,感興趣的朋友跟隨小編一起看看吧2026-02-02
Nginx could not build the server_names_hash 錯誤的解決辦法
這篇文章主要介紹了Nginx could not build the server_names_hash 錯誤的解決辦法,需要的朋友可以參考下2014-03-03
國內(nèi)一些常用PHP的CMS的Nginx服務(wù)器的偽靜態(tài)規(guī)則整理
當(dāng)我們從apache服務(wù)器轉(zhuǎn)向Nginx服務(wù)器的時候,它們的偽靜態(tài)規(guī)則就不一樣了,所以你熟悉Nginx服務(wù)器的偽靜態(tài)規(guī)則,自己寫當(dāng)然也好2011-03-03
Nginx中修復(fù)安全配置漏洞的實(shí)戰(zhàn)指南
這篇文章主要為大家詳細(xì)介紹了Nginx中修復(fù)安全配置漏洞的實(shí)戰(zhàn)指南,文中介紹了如何識別常見的漏洞并進(jìn)行修復(fù),大家可以根據(jù)需要進(jìn)行選擇2025-09-09
nginx出現(xiàn)500 Internal Server Error錯誤的解決方法
這篇文章主要介紹了nginx出現(xiàn)500 Internal Server Error錯誤的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09

