
1 、安装OpenResty
安装使用 OpenResty,这是一个集成了各种 Lua 模块的 Nginx 服务器,是一个以Nginx为核心同时包含很多第三方模块的Web应用服务器,使用Nginx的同时又能使用lua等模块实现复杂的控制。
(1)安装编译工具、依赖库
root@test1 \~\]# yum -y install readline-devel pcre-devel openssl-devel gcc (2)下载openresty-1.13.6.1.tar.gz 源码包,并解压;下载ngx_cache_purge模块,该模块用于清理nginx缓存;下载nginx_upstream_check_module模块,该模块用于ustream健康检查。 cd /usr/local/ wget https://openresty.org/download/openresty-1.13.6.1.tar.gz tar -zxvf openresty-1.13.6.1.tar.gz cd openresty-1.13.6.1/bundle wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz tar -zxvf ngx_cache_purge-2.3.tar.gz wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz tar -zxvf v0.3.0.tar.gz (3)配置需安装的模块 # ./configure --help可查询需要安装的模块并编译安装 ```bash ./configure --prefix=/usr/local/openresty --with-luajit --with-http_ssl_module --user=root --group=root --with-http_realip_module --add-module=./bundle/ngx_cache_purge-2.3/ --add-module=./bundle/nginx_upstream_check_module-0.3.0/ --with-http_stub_status_module make && make install ``` (5)启动nginx /usr/local/openresty/nginx/sbin/nginx -c /usr/local/openresty/nginx/conf/nginx.conf 随后,打开浏览器访问页面。  (6)在Nginx上测试一下能否使用Lua脚本 ```bash vim /usr/local/openresty/nginx/conf/nginx.conf 在server里面加一个 location /lua { default_type text/plain; content_by_lua 'ngx.say("hello,lua!")'; } ```  加完后重新reload配置。 在浏览器里输入 ip地址/lua,出现下面的字就表示Nginx能够成功使用lua了  2 、安装Redis yum install -y redis systemctl start redis 3 、Lua访问Redis (1)连接redis,然后添加一些测试参数 redis-cli set "123" "456" (2)编写连接Redis的Lua脚本 ```bash vim /usr/local/openresty/nginx/conf/lua/redis.lua local redis = require "resty.redis" local conn = redis.new() #根据自己情况写ip和端口号 conn.connect(conn, '192.168.20.205', '6379') local res = conn:get("123") if res==ngx.null then ngx.say("redis集群中不存在KEY------'123'") return end ngx.say(res) ``` (3)在nginx.conf配置文件中的server下添加以下location ```bash vim /usr/local/openresty/nginx/conf/nginx.conf location /lua_redis { default_type text/plain; content_by_lua_file /usr/local/openresty/nginx/conf/lua/redis.lua; } ```  随后重新reload配置。 (4)验证Lua访问Redis的正确性 在浏览器输入ip/lua_redis, 如果能看到下图的内容表示Lua可以访问Redis。  准备工作已经完成,现在要实现OpenResty+Lua+Redis自动封禁并解封IP了。 4 、OpenResty+Lua实现 (1)添加访问控制的Lua脚本(只需要修改Lua脚本中连接Redis的IP和端口即可) **注意:如果在Nginx或者OpenResty的上层有用到阿里云的SLB负载均衡的话,需要修改一下脚本里的所有...ngx.var.remote_addr,把remote_addr替换成从SLB获取真实IP的字段即可,不然获取到的IP全都是阿里云SLB发过来的并且是处理过的IP,同时,这些IP全都是一个网段的,根本没有办法起到封禁的效果)** 完整的Lua脚本如下所示。 ```bash vim /usr/local/openresty/nginx/conf/lua/access.lua local ip_block_time=300 --封禁IP时间(秒) local ip_time_out=30 --指定ip访问频率时间段(秒) local ip_max_count=20 --指定ip访问频率计数最大值(秒) local BUSINESS = ngx.var.business --nginx的location中定义的业务标识符,也可以不加,不过加了后方便区分 --连接redis local redis = require "resty.redis" local conn = redis:new() ok, err = conn:connect("192.168.20.205", 6379) conn:set_timeout(2000) --超时时间2秒 --如果连接失败,跳转到脚本结尾 if not ok then goto FLAG end --查询ip是否被禁止访问,如果存在则返回403错误代码 is_block, err = conn:get(BUSINESS.."-BLOCK-"..ngx.var.remote_addr) if is_block == '1' then ngx.exit(403) goto FLAG end --查询redis中保存的ip的计数器 ip_count, err = conn:get(BUSINESS.."-COUNT-"..ngx.var.remote_addr) if ip_count == ngx.null then --如果不存在,则将该IP存入redis,并将计数器设置为1、该KEY的超时时间为ip_time_out res, err = conn:set(BUSINESS.."-COUNT-"..ngx.var.remote_addr, 1) res, err = conn:expire(BUSINESS.."-COUNT-"..ngx.var.remote_addr, ip_time_out) else ip_count = ip_count + 1 --存在则将单位时间内的访问次数加1 if ip_count >= ip_max_count then --如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time res, err = conn:set(BUSINESS.."-BLOCK-"..ngx.var.remote_addr, 1) res, err = conn:expire(BUSINESS.."-BLOCK-"..ngx.var.remote_addr, ip_block_time) else res, err = conn:set(BUSINESS.."-COUNT-"..ngx.var.remote_addr,ip_count) res, err = conn:expire(BUSINESS.."-COUNT-"..ngx.var.remote_addr, ip_time_out) end end -- 结束标记 ::FLAG:: local ok, err = conn:close() ``` (2)在需要做访问限制的location里加两段代码即可,这里用刚才的/lua做演示 vim /usr/local/openresty/nginx/conf/nginx.conf  主要是添加如下配置: access_by_lua_file /usr/local/openresty/nginx/conf/lua/access.lua; 其中,set $business "lua" 是为了把IP放进Redis的时候标明是哪个location的,可以不加这个配置。随后,重新reload配置。 (3)打开浏览器访问192.168.20.205/lua 并一直按F5刷新。  随后,连接Redis,查看IP的访问计数。 发现redis已经在统计访问lua这个网页ip的访问次数了  这个key的过期时间是30秒,如果30秒没有重复访问20次这个key就会消失,所以说正常用户一般不会触发这个封禁的脚本。 当30秒内访问超过了20次,发现触发脚本了,变成了403  再次查看Redis的key,发现多了一个lua-block-192.168.20.28,过期时间是300秒,就是说在300秒内这个ip无法继续访问192.168.20.205/lua这个页面了。  过五分钟后再去访问这个页面,又可以访问了。 这个脚本的目的很简单:一个IP如果在30秒内其访问次数达到20次则表明该IP访问频率太快了,因此将该IP封禁5分钟。同时由于计数的KEY在Redis中的超时时间设置成了30秒,所以如果两次访问间隔时间大于30秒将会重新开始计数。