通过Consul+nginx map实现零中断动态IP封禁:Consul存黑名单→同步脚本生成map配置→Nginx include热加载→if+return 403拦截新请求,保持已有连接不断开。

在高流量生产环境中,实时封禁恶意 IP 且不中断已有连接,关键在于将黑名单逻辑从应用层下沉到反向代理层,并实现配置热更新。Nginx 本身不支持运行时动态读取 IP 黑名单文件(如 deny 指令需 reload 才生效),但结合 Consul 的 KV 存储与 Watch 机制,配合 Nginx 的 map + geo 模块或第三方模块(如 nginx-upsync-module),可构建零中断的动态黑白名单系统。核心思路是:用 Consul 存储黑名单 IP 列表 → 通过轻量服务监听变更并生成 Nginx 可加载的配置片段 → 利用 include 和 map 实现运行时判断,避免 reload。
一、用 Consul KV 存储结构化黑名单
将黑名单以扁平化 KV 形式存入 Consul,例如:
-
Key:
firewall/blacklist/ip/192.168.1.100,Value:{"reason":"brute-force","expires":"2025-04-10T14:22:00Z"} -
Key:
firewall/blacklist/cidr/10.0.0.0/8,Value:{"reason":"internal-network","permanent":true}
使用 CIDR 格式支持网段匹配,Value 中嵌入元数据便于审计和自动清理。Consul 的 watch 命令或 HTTP long poll 可监听 firewall/blacklist/ 前缀下的所有变更,确保低延迟同步。
二、生成 Nginx 兼容的动态 map 配置
编写一个简短的同步脚本(如 Python 或 Bash),定期或通过 Consul watch 触发,将 KV 数据转换为 Nginx map 指令片段,写入临时文件(如 /etc/nginx/conf.d/dynamic_blacklist.map):
map $remote_addr $is_blocked {
default 0;
"192.168.1.100" 1;
"10.0.0.0/8" 1;
"2001:db8::/32" 1;
}注意:map 支持 CIDR 匹配(Nginx ≥ 1.19.0),无需额外模块;若版本较低,可用 geo 指令替代(语法略有不同,但同样支持 CIDR)。该文件仅包含变量映射逻辑,不触发 reload —— 因为它被 include 进主配置,而 map 块本身支持热重载(只要不修改 map 名称或作用域)。
三、在 server 块中无感拦截,保持长连接
在 Nginx 的 server 或 http 块中引用该 map,并用 if + return 实现拦截:
include /etc/nginx/conf.d/dynamic_blacklist.map;
<p>server {
listen 80;
location / {
if ($is_blocked) {
return 403;
}
proxy_pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a>;</p><h1>其他 proxy_* 配置...</h1><pre class="brush:php;toolbar:false;">}}
关键点:if 在 location 中执行是安全的(非 server 级);return 403 是立即响应,不终止 worker 进程,不影响其他请求;已有 established 连接不受影响,新请求进来时才校验 $is_blocked。整个过程无需 nginx -s reload,也就不会断开 keepalive 连接或重置 TCP 流。
四、增强可靠性与可观测性
上线前建议补充三项实践:
- 同步脚本加锁(如 flock),防止并发写入损坏 map 文件
- map 文件生成后执行
nginx -t校验语法,失败则保留旧版并告警 - 在日志中记录拦截详情,例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $is_blocked';,便于溯源
不复杂但容易忽略。


















