在Nginx中實現(xiàn)動態(tài)封禁IP的三種主流方案
引言
在運維和安全實踐中,經(jīng)常需要根據(jù)實時情況封禁某些惡意 IP。但傳統(tǒng)的Nginx 配置是靜態(tài)的——一旦寫死 deny 1.2.3.4;,就必須重啟或重載服務才能生效。那么,有沒有辦法在不中斷服務的前提下,實現(xiàn)動態(tài)、實時、可編程的 IP 封禁呢?
一、方案對比
| 方案 | 是否需 reload | 實時性 | 技術棧 | 適用場景 |
|---|---|---|---|---|
| geo + map + 文件 | 是(nginx -s reload) | 秒~分鐘級 | 原生 Nginx | 手動或定時腳本封禁 |
| OpenResty + Lua | 否 | 毫秒級 | OpenResty(Nginx + Lua) | 自動化、高并發(fā)、API 化管理 |
| fail2ban + 日志分析 | 否(系統(tǒng)級封禁) | 秒級 | fail2ban + iptables | 安全防護、日志驅(qū)動型封禁 |
二、方案一:原生 Nginx + 外部文件(簡單可靠)
適用于不需要極高實時性的場景,比如每天批量封禁一批掃描 IP。
1. 創(chuàng)建封禁 IP 列表文件
# /etc/nginx/conf.d/blockips.conf 192.168.1.100 1; 203.0.113.5 1;
格式為:IP 值;,值通常設為 1 表示“命中”。
2. 在 nginx.conf 中配置
http {
# 從外部文件加載黑名單
geo $block_ip {
default 0;
include /etc/nginx/conf.d/blockips.conf;
}
map $block_ip $deny_ip {
1 "denied";
0 "";
}
server {
listen 80;
if ($deny_ip = "denied") {
return 403;
}
location / {
# 正常業(yè)務
}
}
}
3. 動態(tài)更新方式
- 修改
blockips.conf - 執(zhí)行平滑重載:
nginx -s reload
? 優(yōu)點:無需額外依賴,配置簡單。
?? 缺點:每次更新需 reload,不適合高頻操作。
三、方案二:OpenResty + Lua(推薦用于自動化)
如果你需要通過 API 實時封禁 IP(例如 WAF、風控系統(tǒng)調(diào)用),OpenResty 是最佳選擇。它基于 Nginx,嵌入 Lua 腳本引擎,支持共享內(nèi)存,無需 reload 即可生效。
1. 安裝 OpenResty
# Ubuntu 示例 wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add - echo "deb http://openresty.org/package/debian $(lsb_release -sc) openresty" | sudo tee /etc/apt/sources.list.d/openresty.list sudo apt update && sudo apt install openresty
2. 配置 nginx.conf
http {
lua_shared_dict ip_blacklist 10m; # 共享內(nèi)存存儲黑名單
server {
listen 80;
# 【核心】訪問前檢查 IP
access_by_lua_block {
local ip = ngx.var.remote_addr
if ngx.shared.ip_blacklist:get(ip) then
ngx.log(ngx.WARN, "Blocked IP: ", ip)
ngx.exit(403)
end
}
# 動態(tài)封禁接口(建議加 IP 白名單保護)
location = /ban {
content_by_lua_block {
local args = ngx.req.get_uri_args()
local ip = args.ip
local seconds = tonumber(args.seconds) or 3600
if not ip or not ip:match("^%d+%.%d+%.%d+%.%d+$") then
ngx.status = 400
ngx.say("Invalid or missing 'ip'")
return
end
ngx.shared.ip_blacklist:set(ip, true, seconds)
ngx.say("Banned ", ip, " for ", seconds, "s")
}
}
# 解封 & 查詢接口
location / { echo "Hello! Your IP: $remote_addr"; }
}
}
3. 使用示例
# 封禁 IP 5 分鐘 curl "http://your-server/ban?ip=1.2.3.4&seconds=300" # 測試是否被封 curl http://your-server/ # 返回 403
? 優(yōu)點:毫秒級生效、支持 TTL 自動過期、可集成到自動化系統(tǒng)。
?? 安全提示:務必限制 /ban 接口的訪問來源!
四、方案三:fail2ban + Nginx 日志(自動防御)
適用于防御暴力 破解、高頻 404 掃描等行為。fail2ban 會監(jiān)控日志,自動封禁異常 IP。
1. 確保 Nginx 記錄詳細日志
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status ...'; access_log /var/log/nginx/access.log main;
2. 創(chuàng)建過濾器 /etc/fail2ban/filter.d/nginx-bad-request.conf
[Definition] failregex = ^<HOST> -.*"(GET|POST).*" 404 .* ignoreregex =
3. 配置 jail(/etc/fail2ban/jail.local)
[nginx-bad-request] enabled = true port = http,https filter = nginx-bad-request logpath = /var/log/nginx/access.log maxretry = 10 # 10 次失敗 findtime = 600 # 在 10 分鐘內(nèi) bantime = 3600 # 封 1 小時 action = iptables-multiport[name=nginx, port="http,https"]
4. 啟動并查看狀態(tài)
sudo systemctl start fail2ban sudo fail2ban-client status nginx-bad-request
? 優(yōu)點:全自動、成熟穩(wěn)定、社區(qū)支持好。
?? 注意:默認使用 iptables 封禁,影響整個服務器,非僅 Nginx。
五、如何選擇?
- 只想偶爾手動封幾個 IP? → 用 方案一(原生 Nginx)。
- 需要程序自動封禁、支持 API 調(diào)用? → 用 方案二(OpenResty)。
- 想自動防御掃描、爆破? → 用 方案三(fail2ban)。
進階技巧:可讓 fail2ban 調(diào)用 OpenResty 的 /ban 接口,實現(xiàn)“僅封 Nginx + 自動過期”的完美組合。
以上就是在Nginx中實現(xiàn)動態(tài)封禁IP的三種主流方案的詳細內(nèi)容,更多關于Nginx動態(tài)封禁IP的資料請關注腳本之家其它相關文章!
相關文章
nginx+rsync+inotify實現(xiàn)負載均衡配置方法
這篇文章主要介紹了nginx+rsync+inotify實現(xiàn)負載均衡配置方法,需要的朋友可以參考下2014-11-11
Debian系統(tǒng)下為PHP程序配置Nginx服務器的基本教程
這篇文章主要介紹了Debian系統(tǒng)下為PHP程序配置Nginx服務器的基本教程,這里使用到了FastCGI和php-fpm,需要的朋友可以參考下2015-12-12
uwsgi+nginx代理Django無法訪問靜態(tài)資源的解決
這篇文章主要介紹了uwsgi+nginx代理Django無法訪問靜態(tài)資源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-05-05
Nginx靜態(tài)文件響應POST請求 提示405錯誤的解決方法
Apache、IIS、nginx等絕大多數(shù)web服務器,都不允許靜態(tài)文件響應POST請求,否則會返回“HTTP/1.1 405 Method not allowed”錯誤2013-04-04

