Ngx+Lua+Redis 实时IP黑名单系统

实时黑名单系统,如果用php脚本实现很容易,但是效率惨不忍睹呀。
要想速度快还的在nginx层实现阻塞。如果iptables 层阻塞速度更快,但是黑名单列表如果有更新就必须要重载配置,实现还是有难度的。php管理后台把黑名单ip写入到redis,nginx层使用lua脚本去redis查询ip是否在黑名单里,实现实时控制。

OpenResty就是嵌入了LuaJIT VM的Nginx,LuaJIT即采用C语言写的Lua代码的解释器。熟悉简单的Lua语言和nginx基础知识就可以上手开发简单功能了。

你可以单独安装OpenResty,如果是宝塔面板也可以直接切换版本 nginx openresty



直接上代码。
整个系统的瓶颈在redis,我们要优化redis连接,需要连接池。

lua_shared_dict my_cache 10m;
server
{ 
.........

先创建一个内存缓存区,名称:my_cache 容量:10m
ngx+lua 中没有全局变量我们需要把redis的链接函数存储到这个 my_cache 里面使用其他地方使用的时候直接读取缓存里的函数代码,再运行函数得到一个redis连接

local my_cache = ngx.shared.my_cache
local redis_connect_code = my_cache:get("redis_connect")

if not redis_connect_code then
    local function redis_connect()
        local redis = require "resty.redis"
        local redis_host = "127.0.0.1"
        local pool_size = 1000
        red = redis:new()
        red:set_timeout(1000) 
        red:set_pool_size(pool_size)
        red:set_keepalive(10000,pool_size)
        red:connect(redis_host,6379)
        red:auth('635241')
        red:select(1)
        return red
    end
    
    redis_connect_code = string.dump(redis_connect)
    my_cache:set('redis_connect',redis_connect_code)
end

local ip = ngx.var.remote_addr

if ip == '192.168.1.102' then
    ngx.exit(ngx.OK)
end

local redis_connect=loadstring(redis_connect_code)
local red=redis_connect()
red:hincrby('store_ip:01',ip,1)
local blacklist, err=red:sismember("store_ip:black",ip)
if blacklist==1 then
    red:hincrby('store_ip:00',ip,1)
    ngx.exit(444)
end

以上是redis连接池代码好黑名单判断代码
把以上代码存储为 access.lua文件放到 /www/server/nginx/conf/ 目录

nginx站点vhosts配置文件

lua_shared_dict my_cache 10m;
server
{
    listen 80;
    listen 443 ssl;
    http2 on;
    ...........
    
    default_type 'application/json';    
    access_by_lua_file /www/server/nginx/conf/access.lua;

在这里解释一点
default_type 'application/json';  强制返回json格式
access_by_lua_file /www/server/nginx/conf/access.lua; 这个代码就是引入上面的黑名单代码。
为什么不把这个代码放到  location / 里面,这样只阻塞api接口。

location / {
        access_by_lua_file /www/server/nginx/conf/access.lua;       
    } 
这样写似乎更规范?
但是我的项目用的是Laravel框架,这个框架需要伪静态配置,
location / {
    try_files $uri $uri/ /index.php?$query_string;
}
这样就 两个location / {}  配置就冲突了。
可不可以把两个 location / 整合到一个里面,是可以的。
但是这个伪静态需要放在所有 location的最后。而黑名单阻塞需要放到所有location的最前面,那就只能不写location  防到外层 server下,这样缺点是,任何请求都会黑名单阻塞,包括请求静态资源,比如一个图片或css文件都会触发黑名单阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hangbobo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值