nginx lua redis 实现ip黑名单

安装LuaJIT

下载地址 http://luajit.org/download.html
这里使用稳定版本2.0.5

wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
tar -zxvf LuaJIT-2.0.5.tar.gz
cd LuaJIT-2.0.5
make -j8
make install 
# 
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.1
`</pre>

## 编译安装lua-nginx-module

> 进入nginx源码目录 nginx -V看下之前的安装都带了哪些参数

<pre class="line-numbers prism-highlight" data-start="1">`./configure  --user=www --group=www \
--prefix=/usr/local/nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-http_realip_module \
--add-module=src/misc/ngx_devel_kit-master  \
--add-module=src/misc/set-misc-nginx-module-master \
--add-module=src/misc/echo-nginx-module-master \
--with-ld-opt=-Wl,-rpath,/usr/local/lib  \
--add-module=/opt/downloads/lua-nginx-module-master
`</pre>

> 后面的就都会了吧

<pre class="line-numbers prism-highlight" data-start="1">`make -j8
make install 
`</pre>

## 验证安装是否正确

> 在nginx里面设置这个

<pre class="line-numbers prism-highlight" data-start="1">`location /hello_lua { 
      default_type 'text/plain'; 
      content_by_lua 'ngx.say("hello, lua")'; 
}
`</pre>

访问显示hello, lua说明lua-nginx-module安装成功了~~~

## 正式配置nginx lua

> lua_shared_dict ip_blacklist 1m;

<pre class="line-numbers prism-highlight" data-start="1">`lua_shared_dict ip_blacklist 1m;
server
{
    ......
}
`</pre>

由 Nginx 进程分配一块 1M 大小的共享内存空间,用来缓存 IP 黑名单

## 安装lua-resty-redis

> 到GitHub上面直接下载解压就OK了

<pre class="line-numbers prism-highlight" data-start="1">`wget https://github.com/openresty/lua-resty-redis/archive/master.zip
mv master.zip lua-resty-redis.zip
unzip lua-resty-redis.zip
cd lua-resty-redis-master/
mv lua-resty-redis-master lua-resty-redis
mv lua-resty-redis /usr/local/nginx/lua
`</pre>

> 配置nginx配置

<pre class="line-numbers prism-highlight" data-start="1">`lua_package_path /usr/local/nginx/lua/lua-resty-redis/lib/resty/redis.lua;
server
{
    ......
}
`</pre>

## 编写脚本

<pre class="line-numbers prism-highlight" data-start="1">`/usr/local/nginx/lua/ip_blacklist.lua
`</pre>

## 配置nginx vhost

> 在location中加入代码

<pre class="line-numbers prism-highlight" data-start="1">`location / {
        access_by_lua_file lua/ip_blacklist.lua;
    }
`</pre>

## 配置黑名单

> 加入黑名单

在redis-cli中  `SADD ip_blacklist 10.1.1.1`

> 移除黑名单

在redis-cli中  `SREM ip_blacklist 10.1.1.1`

* * *

## 脚本如下

<pre class="line-numbers prism-highlight" data-start="1">`-- a quick LUA access script for nginx to check IP addresses against an
-- `ip_blacklist` set in Redis, and if a match is found send a HTTP 403.
--
-- allows for a common blacklist to be shared between a bunch of nginx
-- web servers using a remote redis instance. lookups are cached for a
-- configurable period of time.
--
-- block an ip:
--   redis-cli SADD ip_blacklist 10.1.1.1
-- remove an ip:
--   redis-cli SREM ip_blacklist 10.1.1.1
--
-- also requires lua-resty-redis from:
--   https://github.com/agentzh/lua-resty-redis
--
-- your nginx http context should contain something similar to the
-- below: (assumes resty/redis.lua exists in /etc/nginx/lua/)
--
--   lua_package_path "/etc/nginx/lua/?.lua;;";
--   lua_shared_dict ip_blacklist 1m;
--
-- you can then use the below (adjust path where necessary) to check
-- against the blacklist in a http, server, location, if context:
--
-- access_by_lua_file /etc/nginx/lua/ip_blacklist.lua;
--
-- from https://gist.github.com/chrisboulton/6043871
-- modify by Ceelog

local redis_host    = "127.0.0.1" -- 这里一定是redis的IP地址
local redis_port    = "6379"

-- connection timeout for redis in ms. don't set this too high!
local redis_connection_timeout = 1000

-- check a set with this key for blacklist entries
local redis_key     = "ip_blacklist"

-- cache lookups for this many seconds
local cache_ttl     = 60

-- end configuration

local ip                = ngx.var.remote_addr
local ip_blacklist              = ngx.shared.ip_blacklist
local last_update_time  = ip_blacklist:get("last_update_time");

-- only update ip_blacklist from Redis once every cache_ttl seconds:
if last_update_time == nil or last_update_time &lt; ( ngx.now() - cache_ttl ) then

  local redis = require "resty.redis";
  local red = redis:new();

  red:set_timeout(redis_connect_timeout);

  local ok, err = red:connect(redis_host, redis_port);

  if not ok then
    ngx.say("failed to authenticate: ", err)
    return
    ngx.log(ngx.DEBUG, "Redis connection error while retrieving ip_blacklist: " .. err);
  else
    local res, err = red:auth("123123") -- 配置redis的密码

    if not res then
        ngx.say("failed to authenticate: ", err)
        return
    end
    red:select(2) -- 设置redis的db
    local new_ip_blacklist, err = red:smembers(redis_key);
    if err then
      ngx.log(ngx.DEBUG, "Redis read error while retrieving ip_blacklist: " .. err);
    else
      -- replace the locally stored ip_blacklist with the updated values:
      ip_blacklist:flush_all();
      for index, banned_ip in ipairs(new_ip_blacklist) do
        ip_blacklist:set(banned_ip, true);
      end

      -- update time
      ip_blacklist:set("last_update_time", ngx.now());
    end
  end
end

if ip_blacklist:get(ip) then
  --ngx.say(ip)
  ngx.log(ngx.DEBUG, "Banned IP detected and refused access: " .. ip);
  return ngx.exit(ngx.HTTP_FORBIDDEN);
end