init_by_lua_block {
    redis = require "redis"
    client = redis.connect('127.0.0.1', 6379)
}
server {
    listen 8080;
    location  / {
        access_by_lua_file /usr/local/nginx/conf/lua/block.lua;
        proxy_pass http://192.168.1.102:8000;
    }
}
-- Redis-based IP rate limiting / blocking for OpenResty (ngx_lua)

-- NOTE:
-- This script assumes a global `client` variable is used/stored.
-- Make sure `redis` module is available and `client` is initialized somewhere.

local function isConnected()
    return client:ping()
end

local function createRedisConnection()
    return redis.connect("127.0.0.1", 6379)
end

-- 如果发生 redis 连接失败,将停止拦截(直接放行)
if pcall(isConnected) then
    -- already connected (or ping succeeded)
else
    -- not connected; try reconnect
    if pcall(createRedisConnection) then
        -- 断开重连:会导致每次访问都需要重连 redis
        -- 访问量大时建议:关闭重连逻辑(pcall 不执行),直接 ngx.exit 放行/终止
        client = createRedisConnection()
    else
        ngx.exit(ngx.OK)
    end
end

local ttl = 60         -- 监测周期(秒)
local bktimes = 30     -- 在监测周期内达到触发拦截的访问量
local block_ttl = 600  -- 触发拦截后拦截时间(秒)

local ip = ngx.var.remote_addr
local ipvtimes = client:get(ip)

if ipvtimes then
    if ipvtimes == "-1" then
        -- blocked
        return ngx.exit(403)
    else
        local last_ttl = client:ttl(ip)
        -- ngx.say("key exist.ttl is ", last_ttl)

        if last_ttl == -1 then
            client:set(ip, 0)
            client:expire(ip, ttl)
            -- ngx.say("ttl & vtimes recount")
            return ngx.exit(ngx.OK)
        end

        local vtimes = tonumber(client:get(ip)) + 1

        if vtimes < bktimes then
            client:set(ip, vtimes)
            client:expire(ip, last_ttl)
            -- ngx.say(ip, " view ", vtimes, " times")
            return ngx.exit(ngx.OK)
        else
            -- ngx.say(ip, " will be block next time.")
            client:set(ip, -1)
            client:expire(ip, block_ttl)
            return ngx.exit(ngx.OK)
        end
    end
else
    -- key does not exist
    client:set(ip, 1)
    -- ngx.say(ip, " view 1 times")
    client:expire(ip, ttl)
    return ngx.exit(ngx.OK)
end