nginx全局ip黑名单需用geo+map+include实现,禁用直接deny;通过独立blacklist.conf管理ip,配合limit_req限流与日志分析脚本自动更新,兼顾性能、可维护性与误伤控制。

在 Nginx 中配置全局 IP 访问黑名单抵御扫描,核心是把封禁逻辑放在 http 块,覆盖所有 server 和 location,同时兼顾性能、可维护性与误伤控制。不推荐用大量 deny 指令直接写死在 http 块——Nginx 不支持该用法,会报错;必须通过 geo + map + include 组合实现真正可行的“全局黑名单”。
用 geo + map 实现高性能全局封禁
这是最稳定、零依赖、低开销的方式。Nginx 在启动时解析 geo 变量,后续请求仅做内存比对,无文件 I/O 或正则开销。
- 在
http块顶部添加:
geo $is_blocked {
default 0;
include /etc/nginx/conf.d/blacklist.conf;
}
- 紧接着定义布尔映射:
map $is_blocked $blocked {
1 "1";
default "";
}
- 在所有需要防护的
location中统一拦截(例如放在server块的通用 location 或使用if放在location /内):
if ($blocked) {
return 403;
}
把黑名单规则抽成独立文件管理
将 IP 列表从主配置中解耦,便于脚本自动更新、多人协作或跨站点复用。
- 创建文件
/etc/nginx/conf.d/blacklist.conf,内容格式为每行一个 IP 或网段:
# 示例
192.168.0.0/16 0;
10.0.0.0/8 0;
203.0.113.5 1;
198.51.100.0/24 1;
- 注意:前面两行是白名单豁免(如内网段),避免误封;后面是真正要封的恶意 IP/段;值为
1表示触发封禁 - 每次修改后必须执行
nginx -t && nginx -s reload才生效
配合限流提前压制扫描行为
纯黑名单有滞后性——攻击已发生才封。建议在关键路径叠加 limit_req,把高频试探流量压下来,降低日志污染和误判风险。
- 在
http块定义限流区域:
limit_req_zone $binary_remote_addr zone=scan_limit:10m rate=5r/m;
- 在敏感 location(如根路径、登录页、后台入口)启用:
location / {
limit_req zone=scan_limit burst=8 nodelay;
if ($blocked) { return 403; }
# 后续 proxy_pass 或 try_files
}
- 这样:先限流 → 触发限流的 IP 进入冷却期 → 日志分析脚本再将其写入黑名单 → 下次请求直接 403
扫描行为识别与黑名单自动更新(简要示意)
真正的“自动”靠外部脚本驱动,不是 Nginx 自身能力。典型逻辑如下:
- 定时(如每 2 分钟)分析 access.log,筛选出短时间高频访问敏感路径(如
/wp-login.php、/admin/、/phpmyadmin/)的 IP - 过滤掉白名单网段(如公司出口 IP)
- 生成新
blacklist.conf,覆盖旧文件 - 执行
nginx -t && nginx -s reload完成热更新
脚本示例片段(可放入 cron):
awk -v d="$(date -d '2 minutes ago' '+%d/%b/%Y:%H:%M')" \
'$0 ~ d && $7 ~ /\/wp-login|\/admin\/ && $9 == 404 {print $1}' \
/var/log/nginx/access.log | sort | uniq -c | awk '$1 > 10 {print $2}' \
| grep -v -E '^(192\.168|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)' \
> /etc/nginx/conf.d/blacklist.conf.tmp && \
mv /etc/nginx/conf.d/blacklist.conf.tmp /etc/nginx/conf.d/blacklist.conf











