zoukankan      html  css  js  c++  java
  • Nginx 通过 Lua + Redis 实现动态封禁 IP

    一 、安装 Openrestry

    # 1.下载源码包
    wget https://openresty.org/download/openresty-1.11.2.2.tar.gz
    tar -xzvf openresty-1.11.2.2.tar.gz
    cd openresty-1.11.2.2
    
    # 2.查看 nginx 编译选项:
    $ nginx -V
    nginx version: nginx/1.10.3
    ... (省略) ...
    # 3. 编译安装 
    ./configure   --prefix=/usr/local/openresty --with-luajit --without-http_redis2_module --with-http_stub_status_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --with-openssl=/usr/local/src/openssl-1.0.2m
    
    make
    make install

    二 、 配置 openrestry

    # 复制原来的 `nginx` 配置
    #openresty-nginx 路径是: /usr/local/openresty/nginx
    #将原来的nginx 配置都复制到 /usr/local/openresty/nginx/conf
    
    cp /usr/local/nginx/conf/*.conf /usr/local/openresty/nginx/conf/
    ## vhost 目录  ssl 目录
    cp -r /usr/local/nginx/conf/conf.d /usr/local/openresty/nginx/conf
    
    还要根据服务器实际情况,修改 nginx.conf 等配置文件中替换路径为新的路径

    三、 修改环境变量

    1. 先停止原来的nginx
    2. 添加环境变: 
      PATH=/usr/local/openresty/nginx/sbin:$PATH 
      export PATH
       
      改了之后原来的nginx 就没用了,这里我本来就是替换的,所以就这样设置了。
    3. 执行 :source /etc/profile
    4. 运行 openresty $ nginx

    注意:openresty 在支持http2的时候 响应头header server会修改成nginx

    # 验证版本
    root@iZm5eabkgmsfy2phj5pr1xZ:~$ nginx -V
    nginx version: openresty/1.11.2.2
    built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
    built with OpenSSL 1.0.2m  2 Nov 2017
    TLS SNI support enabled
    configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 —add-(省略)

    这里写图片描述

    这里写图片描述

    四、 使用 lua-redis 实现封禁ip高频访问

    1. 查看 access.log 高访问前5条数据

    awk '{print $1}' access.log | sort|uniq -c | sort -nr | head -n 5
    
    8 180.169.120.218
    1 40.77.167.22
    1 207.46.13.192
    ...

    2. 修改 nginx 配置 ,nginx.conf 或者 虚拟主机host 中,添加对 lua 脚本的支持

    # 以我自己服务器为例,我的www.leon0204.com 的配置文件在 
    $ cd  /usr/local/openresty/nginx/conf/conf.d/  && vim  leon0204.conf
    
    # 添加 openrestry 引入lua脚本要用的地址
    lua_package_path "/usr/local/openresty/lualib/resty/redis.lua;";#告诉openresty库地址
    #lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
    error_log /usr/local/openresty/nginx/logs/openresty.debug.log debug;
    
    # 所有 xxx/hello 的请求会被分发给lua 脚本处理
    location /hello {
            default_type text/html;
            access_by_lua_file "/usr/local/openresty/nginx/lua/access_by_redis.lua";
    
     }

    3. lua 的基于访问频率的reids 实现自动化可控封禁脚本

    # Lua
    local function close_redis(red)
        if not red then
            return
        end
        --释放连接(连接池实现)
        local pool_max_idle_time = 10000 --毫秒
        local pool_size = 100 --连接池大小
        local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)
    
        if not ok then
            ngx_log(ngx_ERR, "set redis keepalive error : ", err)
        end
    end
    
    -- 连接redis
    local redis = require('resty.redis')
    local red = redis.new()
    red:set_timeout(1000)
    
    local ip = "127.0.0.1"  ---修改变量
    local port = "6379" ---修改变量
    local ok, err = red:connect(ip,port)
    if not ok then
        return close_redis(red)
    end
    red:auth('passwd')
    --resp = redis_init:set('funet', '888888')
    --resp = redis_init:get('funet')
    
    
    
    
    local clientIP = ngx.req.get_headers()["X-Real-IP"]
    if clientIP == nil then
       clientIP = ngx.req.get_headers()["x_forwarded_for"]
    end
    if clientIP == nil then
       clientIP = ngx.var.remote_addr
    end
    
    --ngx.say(clientIP)
    
    --if clientIP == "101.231.137.70" then
    --    ngx.exit(ngx.HTTP_FORBIDDEN)
    --       return close_redis(red)
    --    end
    
    local incrKey = "user:"..clientIP..":freq"
    local blockKey = "user:"..clientIP..":block"
    
    local is_block,err = red:get(blockKey) -- check if ip is blocked
    --ngx.say(tonumber(is_block))
    if tonumber(is_block) == 1 then
        --ngx.say(3)
        ngx.exit(403)
        --ngx.exit(ngx.HTTP_FORBIDDEN)
        close_redis(red)
    end
    
    inc  = red:incr(incrKey)
    
    
    ngx.say(inc)
    
    if inc < 2 then
       inc = red:expire(incrKey,1)
    end
    
    if inc > 2 then --每秒2次以上访问即视为非法,会阻止1分钟的访问
        red:set(blockKey,1) --设置block 为 True 为1
        red:expire(blockKey,60)
    end
    
    close_redis(red)
    

    最终效果:

    1. 在一秒内访问1,2次,nginx 返回 1,2
    2. 一秒访问3次,直接返回 403 ,参数可控 ,封禁时间可控 
      这里写图片描述
    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28018283/article/details/79478838
  • 相关阅读:
    【转】Linux 用cp和rsync同步文件时跳过指定目录
    解决svn错误:postcommit hook failed (exit code 1) with output
    Linux下如何使cp命令不提示覆盖文件
    Linux tar压缩时排除某个目录或文件的参数
    ecshop中404错误页面 .
    Linux如何查看当前目录下文件的个数
    Meta Property=og标签在SEO中的应用
    mysql mysqldump只导出表结构或只导出数据的实现方法
    slaveskiperrors( 转)
    自定义404错误页面返回状态码分析
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/9518091.html
Copyright © 2011-2022 走看看