# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://close.gitbook.io/yun-wei-bi-ji/centos/nginx/ngx_lua.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
