nginx黑名单需通过geo+map配置固化+外部脚本动态更新实现;推荐geo+map方案处理数千条规则,deny指令适用于临时封禁,配合日志分析脚本与limit_req限流可提升响应精度和稳定性。

Nginx 本身不支持运行时自动识别并封禁恶意 IP,黑名单机制必须靠“配置+外部协同”实现。核心思路是:把黑名单规则固化进配置逻辑,再通过外部脚本动态更新规则文件,最后平滑重载生效。整个过程不依赖第三方模块,稳定、轻量、可落地。
用 geo + map 实现高性能静态黑名单
这是最推荐的基础方案,适合中低频更新、规则数量在数千条以内的场景:
- 在 http 块顶部定义 geo 变量,将黑名单 IP 映射为 1,其余为 0:
geo $bad_ip {
default 0;
include /usr/local/nginx/conf/blacklist.conf;
} - 再用 map 将数值转为布尔标记,便于后续判断:
map $bad_ip $blocked {
1 "1";
default "";
} - 在具体 location 中拦截(如登录页、API 入口):
location = /wp-login.php {
if ($blocked) { return 403; }
# 其他配置...
}
用 allow/deny 指令快速临时封禁
适合手动应急、规则极少(几十条以内)、无需复用的场景:
- 黑名单逻辑是“先 deny,后 allow all”,但 allow all 可省略(Nginx 默认放行):
location / {
deny 203.0.113.5;
deny 198.51.100.0/24;
# 不需要写 allow all
} - 务必放在 server 或 location 块内,不能写在 http 全局层;多个站点需各自配置,互不影响
- 支持 IPv4、IPv6 和 CIDR 网段,例如:
deny 2001:db8::/32;
配合脚本实现半自动动态封禁
纯静态黑名单有滞后性,建议搭配日志分析脚本提升响应速度:
- 定时任务(如每 2 分钟)执行 shell 脚本,筛选出高频扫描行为:
例如:统计过去 2 分钟内对/wp-login.php或/admin/的请求超 15 次的 IP - 脚本生成新
blacklist.conf,**自动排除白名单网段**(如192.168.0.0/16、10.0.0.0/8),避免误封 - 关键一步:执行
nginx -t && nginx -s reload,语法校验通过才重载,防止服务中断
叠加限流降低攻击冲击和误判
单纯封禁无法应对突发流量,建议前置限流作为缓冲:
- 对敏感路径启用
limit_req,例如登录接口限制为每分钟 3 次:
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=3r/m;
location = /wp-login.php {
limit_req zone=login_limit burst=5 nodelay;
} - 被限流的 IP 更可能属于恶意行为,可作为脚本写入黑名单的高置信度信号,比直接封更稳妥
- 避免在全局 server 块滥用
if,所有拦截逻辑收束到具体 location,减少性能损耗











