# Ngx\_lua



* ngx\_cache\_purge 缓存使用，(如果不会lua开发，不需要安装)
* nginx\_upstream\_check\_module 流量分发使用，(如果不会lua开发，不需要安装)

### 部署 openresty

```python
mkdir -p /usr/servers  
cd /usr/servers/
# 安装依赖
yum install -y readline-devel pcre-devel openssl-devel gcc

# 可能需要翻墙才能下载，所以可以离线下载好
wget http://openresty.org/download/ngx_openresty-1.7.7.2.tar.gz  
tar -xzvf ngx_openresty-1.7.7.2.tar.gz  
rm -rf ngx_openresty-1.7.7.2.tar.gz

# 安装 lua 等相关组件
cd /usr/servers/ngx_openresty-1.7.7.2/
cd bundle/LuaJIT-2.1-20150120/  
make clean && make && make install  
ln -sf luajit-2.1.0-alpha /usr/local/bin/luajit
cd ../
wget https://github.com/FRiCKLE/ngx_cache_purge/archive/2.3.tar.gz  
tar -xvf 2.3.tar.gz  
wget https://github.com/yaoweibin/nginx_upstream_check_module/archive/v0.3.0.tar.gz  
tar -xvf v0.3.0.tar.gz  

#
cd /usr/servers/ngx_openresty-1.7.7.2  
./configure --prefix=/usr/servers --with-http_realip_module  --with-pcre  --with-luajit --add-module=./bundle/ngx_cache_purge-2.3/ --add-module=./bundle/nginx_upstream_check_module-0.3.0/ -j2  
make && make install

# 会发现多了好多目录
[root@eshop-cache01 servers]# ll
total 3316
drwxr-xr-x 2 root root    4096 Apr  1 23:38 bin
drwxr-xr-x 6 root root    4096 Apr  1 23:38 luajit
drwxr-xr-x 5 root root    4096 Apr  1 23:38 lualib
drwxr-xr-x 6 root root    4096 Apr  1 23:38 nginx
drwxrwxr-x 4 1000 1000    4096 Apr  1 23:35 ngx_openresty-1.7.7.2

# 启动nginx:
/usr/servers/nginx/sbin/nginx
```

### 添加 lua 模块到 nginx 中

```python
vi /usr/servers/nginx/conf/nginx.conf

# 在 http 部分添加如下内容


如下位置

http {
    # 添加模块
    lua_package_path "/usr/servers/lualib/?.lua;;";
    lua_package_cpath "/usr/servers/lualib/?.so;;";

    include       mime.types;
    default_type  application/octet-stream;
    。。。。。。

  }
```

### 结合 redis 防 CC 设置

```python
[root@k3s-master conf]# cat waf/LimitRate.lua 
--加载 REDIS 模块
local r_md = require "resty.redis"

--获取当前请求的 HEADER
local headers = ngx.req.get_headers()

--指定 REDIS 的地址、端口、密码、连接的空闲超时时间、接池大小
local redis_ip = "127.0.0.1"
local redis_port = "6379"
local redis_pass = "123456"
local redis_timeout = 1000
local redis_pool_max_idle_time = 1000
local redis_pool_size = 100

--建立 redis 实例
local redis = r_md:new()

--指定IP存储超时时间
local qtrange = 60

--允许在IP存储时间内访问的次数
local qcount = 10

--尝试根据 HTTP 头遂级获取 IP
local clientip = headers["X-Real-IP"]
if clientip == nil then
   clientip = headers["x_forwarded_for"]
end
if clientip == nil then
   clientip = ngx.var.remote_addr
end

--释放 redis 连接的函数
local function redis_close(red)

  --释放连接，使用 set_keepalive 指令将当前连接放入当前进程的连接池中待用，需要指定连接池的大小及其中各个连接的空闲超时时间；
  local pool_max_idle_time = redis_pool_max_idle_time --毫秒
  local pool_size = redis_pool_size --连接池大小
  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


--选择的桶
--red:select(18)


--建立连接，若异常则释放连接；
local ok, wrong = redis:connect(redis_ip,redis_port)
if not ok then
    redis_close(redis)
end



--指定所有 REDIS 操作的超时时间，其中包含了连接超时
redis:set_timeout(redis_timeout)
redis:auth(redis_pass)

--建立限速类
LimitIpRate = {}

--限速方法，令牌桶限速逻辑实现
function LimitIpRate:is_limited()

    --尝试获取当前 IP 的令牌桶，令牌桶命名为“ x.x.x.x|pool ”
    local res, err = redis:get(clientip.."|pool")
    if not res then
        ngx.log(ngx.ERR,"lua error: ",err)
    end

    --如果 res 不为空并且类型为 string，则代表获取到了对应的令牌桶
    if type(res) == "string" then
    
        --可用令牌数量为 0 则拦截
        if tonumber(res) == 0 then
            ngx.exit(ngx.HTTP_FORBIDDEN)
            
        --反之放行并让令牌数量减少 1
        else
            add,err = redis:decr(clientip.."|pool")
            if not add then
                ngx.log(ngx.ERR,"lua error: ",err)
            end
        end
    
    --如果 res 不为空并且类型为 userdata，则代表 redis 中没有对应令牌桶
    elseif type(res) == "userdata" then
        
        --往 redis 中放入指定名称、过期时间、值的键值对
        ini, err = redis:setex(clientip.."|pool", qtrange, (qcount-1))
        if not ini then
            ngx.log(ngx.ERR,"lua error: ",err)
        end
    end
end
    
--调用限速方法
LimitIpRate.is_limited()
```

```bash
        location / {
            root   html;
            index  index.html index.htm;
            access_by_lua_file "conf/waf/LimitRate.lua"; # 添加如下
        }
```

### 测试效果

```bash
[root@localhost ~]# for i in {1..12}; do curl -s 10.11.9.246 -o /dev/null -w %{http_code};echo ;done
200
200
200
200
200
403
403
403
403
403
403
403
```

参考: https://zq99299.github.io/note-book/cache-pdp/052.html#%E9%83%A8%E7%BD%B2-openresty
