Nginx 通过 Lua + Redis 实现动态封禁 IP

Nginx 通过 Lua + Redis 实现动态封禁 IP
最新回答
北蒙岛的雨季

2022-05-01 17:45:30

Nginx 通过 Lua + Redis 实现动态封禁 IP 的方案,是一种高效、灵活且可扩展的解决方案。以下是具体实现步骤和关键要点:

一、方案优势
  1. 动态管理:黑名单可实时更新,无需重启 Nginx。
  2. 共享性:多台 Nginx 服务器可通过 Redis 共享同一黑名单。
  3. 低性能开销:利用共享内存和 Redis 的高效查询,减少对服务器性能的影响。
二、实现步骤1. 环境准备
  • 安装 OpenResty(推荐)OpenResty 是集成了 Lua 模块的 Nginx 发行版,简化配置:

    # 以 Ubuntu 为例sudo apt-get install -y openresty
  • 安装 Redis

    sudo apt-get install -y redis-serversudo systemctl start redis
2. Nginx 配置

在 nginx.conf 的 http 块中添加共享内存和 Lua 脚本路径:

http { lua_shared_dict ip_blacklist 1m; # 1MB 共享内存缓存黑名单 server { listen 80; location / { access_by_lua_file /path/to/lua/ip_blacklist.lua; # 指定 Lua 脚本 proxy_pass
http://backend;
} }}

3. Lua 脚本实现

创建 /path/to/lua/ip_blacklist.lua,实现以下逻辑:

  • 检查共享内存缓存:优先从本地缓存查询。
  • 回源 Redis:若缓存未命中,则从 Redis 获取最新黑名单并更新缓存。
  • 封禁逻辑:若 IP 在黑名单中,返回 403 状态码。
local blacklist = ngx.shared.ip_blacklistlocal redis = require "resty.redis"local red = redis:new()-- 连接 Redisred:connect("127.0.0.1", 6379)-- 获取客户端 IPlocal client_ip = ngx.var.remote_addr-- 检查共享内存缓存local is_blocked = blacklist:get(client_ip)if not is_blocked then -- 回源 Redis 查询 is_blocked = red:sismember("ip_blacklist", client_ip) if is_blocked == 1 then -- 更新本地缓存(有效期 60 秒) blacklist:set(client_ip, true, 60) endend-- 封禁逻辑if is_blocked == 1 then ngx.log(ngx.WARN, "Blocked IP: ", client_ip) ngx.exit(ngx.HTTP_FORBIDDEN)end-- 关闭 Redis 连接red:set_keepalive(10000, 100)

4. Redis 数据初始化

在 Redis 中创建黑名单集合,并添加 IP:

redis-cli> SADD ip_blacklist "192.168.1.100" "10.0.0.5"5. 验证效果
  • 被封禁 IP 访问:返回 403 Forbidden。
  • 正常 IP 访问:正常代理到后端服务。
三、关键优化点
  1. 缓存策略

    共享内存(lua_shared_dict)减少 Redis 查询频率。

    设置合理的缓存过期时间(如 60 秒),平衡实时性和性能。

  2. Redis 高可用

    使用 Redis 集群或哨兵模式避免单点故障。

  3. 自动化管理

    通过脚本或监控系统(如 Prometheus + Grafana)动态更新 Redis 黑名单。

  4. 日志记录

    在 Lua 脚本中记录封禁事件,便于审计(如 ngx.log)。

四、架构图示

流程说明
  1. 客户端请求到达 Nginx。
  2. Lua 脚本检查共享内存 → 未命中则查询 Redis。
  3. 若 IP 在黑名单中,返回 403;否则放行并代理到后端。
五、总结

此方案通过 Nginx + Lua + Redis 实现了动态、高效、可共享的 IP 黑名单机制,适用于以下场景:

  • 防御恶意爬虫或 DDoS 攻击。
  • 多服务器协同封禁。
  • 需要频繁更新黑名单的业务(如风控系统)。

注意事项

  • 确保 Redis 和 Nginx 的网络连通性。
  • 监控 Lua 脚本的执行性能(如 ngx.timer 避免阻塞)。
  • 定期清理共享内存中的过期数据。