虽然说 Nginx 的标准模块非常强大,然而如果遇到了一些不能灵活适应系统要求的功能时候,我们往往会考虑使用 Lua 拓展和定制 Nginx 服务,目前对于这种需要拓展性的项目一般采用 OpenResty ,按照官方的介绍,OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态Web 应用、Web 服务和动态网关

但是,有的时候服务已经部署完成,包括配置都已经写好了,直接对线上的 Nginx 进行替换显然是一种非常冒险与费神的行为,又或者是只需要某一项功能的拓展,并不需要整体做大改动,这个时候用 Lua 模块就是一种很好的选择。

模拟线上环境

这里我启用了虚拟机作为线上的机器,因此需要重新安装 Nginx,Arguments 这边是需要单独记下来的,和后面编译做到尽量一个参数,这样对配置文件不会造成任何影响

$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo apt install nginx

$ nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-d4S6DH/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

编译包含了 Lua 模块的 Nginx

$ mkdir nginx && cd nginx
$ wget https://nginx.org/download/nginx-1.18.0.tar.gz
$ tar xvf nginx-1.18.0.tar.gz

不推荐去 LuaJIT 官网下载 2.0.5 版本,不然在 arm64 下将无法进行编译(M1 Mac)

$ git clone https://github.com/LuaJIT/LuaJIT.git
$ cd LuaJIT 
$ git checkout
Your branch is up to date with 'origin/v2.1'.
$ sudo make install PREFIX=/usr/local/LuaJIT
...
==== Successfully installed LuaJIT 2.1.0-beta3 to /usr/local/LuaJIT ====
$ sudo ln -sf luajit-2.1.0-beta3 /usr/local/LuaJIT/bin/luajit

# 这里写到 zshrc 也行
$ echo "export LUAJIT_LIB=/usr/local/LuaJIT/lib" | sudo tee -a /etc/profile
$ echo "export LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.1" | sudo tee -a /etc/profile
$ source /etc/profile

ngx_devel_kit

$ cd /opt
$ sudo wget https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.1.zip
$ sudo unzip v0.3.1.zip
$ sudo rm v0.3.1.zip

lua-nginx-module

https://github.com/openresty/lua-resty-core/issues/248

$ cd ~/nginx/
$ wget https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.14.zip
$ unzip v0.10.14.zip
$ sudo mv lua-nginx-module-0.10.14 /opt

pcre && openssl && zlib

$ sudo apt install libpcre3 libpcre3-dev

$ wget https://www.openssl.org/source/openssl-1.1.1f.tar.gz
$ tar xvf openssl-1.1.1f.tar.gz
$ sudo mv openssl-1.1.1f /opt

$ wget https://zlib.net/zlib1211.zip
$ unzip zlib1211.zip
$ sudo mv zlib-1.2.11 /opt

根据上面的编译选项附加上我们的内容

$ cd nginx-1.18.0
$ ./configure \
	--with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-d4S6DH/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' \
	--with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' \
	--prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf \
	--http-log-path=/var/log/nginx/access.log \
	--error-log-path=/var/log/nginx/error.log \
	--lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid \
	--modules-path=/usr/lib/nginx/modules \
	--http-client-body-temp-path=/var/lib/nginx/body \
	--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \
	--http-proxy-temp-path=/var/lib/nginx/proxy \
	--http-scgi-temp-path=/var/lib/nginx/scgi \
	--http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit \
	--with-http_ssl_module --with-http_stub_status_module --with-http_realip_module \
	--with-http_auth_request_module --with-http_v2_module --with-http_dav_module \
	--with-http_slice_module --with-threads --with-http_addition_module \
	--with-http_gunzip_module --with-http_gzip_static_module \
	--with-http_sub_module --with-ld-opt=-Wl,-rpath,/usr/local/LuaJIT/lib \
	--add-module=/opt/ngx_devel_kit-0.3.1 \
	--add-module=/opt/lua-nginx-module-0.10.14 \
	--with-openssl=/opt/openssl-1.1.1f \
	--with-zlib=/opt/zlib-1.2.11
$ make -j$(cat /proc/cpuinfo | grep -c processor)
$ cp $(which nginx) /tmp/
$ sudo systemctl stop nginx
$ sudo cp objs/nginx $(which nginx)
$ sudo systemctl restart nginx.service

测试

$ curl get.docker.io -L | sudo bash -
$ sudo docker run -it -p 8080:80 --name nginx -d nginx # 当成正常的网页
$ sudo apt install build-essential libreadline-dev unzip
$ curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz
$ tar xvf lua-5.4.4.tar.gz
$ cd lua-5.4.4
$ make linux test
$ sudo make install && lua -v
Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio

$ wget https://luarocks.org/releases/luarocks-3.8.0.tar.gz
$ tar zxpf luarocks-3.8.0.tar.gz
$ cd luarocks-3.8.0
$ ./configure --with-lua-include=/usr/local/include
$ make && sudo make install
$ luarocks install lua-resty-http
Installing https://luarocks.org/lua-resty-http-0.17.0.beta.1-0.src.rock

lua-resty-http 0.17.0.beta.1-0 depends on lua >= 5.1 (5.4-1 provided by VM)
No existing manifest. Attempting to rebuild...
lua-resty-http 0.17.0.beta.1-0 is now installed in /home/sxueck/lua/lua-5.4.4/luarocks-3.8.0/./lua_modules (license: 2-clause BSD)

Lua 代码

---
--- Created by sxueck.
--- DateTime: 2022/2/23 11:31
---

ngx.header.content_type = "text/html"
ngx.header.PowerBy = "Lua"

for k, v in pairs(ngx.req.get_headers()) do
    if k == "gray" then
        if v == "true" then
            ngx.say("this's gray page")
            return
        end
    end
end

local httpc = require("resty.http").new()
local res, err = httpc:request_uri("https://www.baidu.com", nil)

if not res then
    ngx.log(ngx.ERR, "request failed: ", err)
else
    ngx.say(res.body)
end