南琴浪博客

开始使用 ngx_lua

04/18/2018

说到 Lua 肯定就想到 OpenResty 了,由国人章亦春(我不会告诉你们人称“春哥”的)等发起的一个基于 Nginx 与 Lua 的高性能 Web 平台。以下简略引用 OpenResty 官网的描述:

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

经过一段时间的折(zuo)腾(si),我也总算是学会 Lua 的最最基本写法了。

不过因为暂时我还用(mei)不(xue)上(hui) OpenResty 那么强大的套装,本文仅介绍单独将 lua-nginx-module 引入 Nginx 的方法。

lua-nginx-module

要引入 Lua 到 Nginx,最简化的操作就是仅引入 lua-nginx-moduleluajit 两者,不过建议同时引入 ngx_devel_kit 模块。对这三者简单介绍下:

  • lua-nginx-module:是 Lua 的最基本模块
  • luajit:官网,luajit 是采用 C 语言编写的 Lua 语言解释器。当然如果你不想用 luajit 的话,也可以 yum 安装 lua 并提供给 Nginx,不推荐那样而已
  • ngx_devel_kit:一般简称 NDK,是一个供其它模块使用的拓展 Nginx 核心功能的模块,第三方模块开发可以基于它快速实现。强烈建议编译 Lua 时把它也带上,虽然不是必须的,缺少该依赖项时例如 set_by_lua* 和 ndk.set_var.* API 都将被自动禁用

开始编译,首先要准备 luajit 库。master 提供的是 2.0.5 版本,大概毛病比较多,不建议采用。这里我选择春哥的 2.1.0 beta3 分支:

git clone --branch=v2.1-agentzh https://github.com/openresty/luajit2.git
cd luajit2

# make 和 make install 的路径需要记下来(使用绝对路径),之后定义变量要用
make PREFIX=.../ngx_lua/luajit/made
make install PREFIX=.../ngx_lua/luajit/makeinstalled

# 然后需要配置一下 luajit 的环境变量 (Nginx编译时需要)
export LUAJIT_LIB=.../ngx_lua/luajit/makeinstalled/lib
export LUAJIT_INC=.../ngx_lua/luajit/makeinstalled/include/luajit-2.1

然后克隆 lua-nginx-module 和 ngx_devel_kit 下来,并进行编译 Nginx:

# 下载 lua-nginx-module
git clone https://github.com/openresty/lua-nginx-module.git

# 下载 ngx_devel_kit
git clone https://github.com/simplresty/ngx_devel_kit.git

# 下载 Nginx
# 这里选择 Nginx 1.14.0 stable (via: https://nginx.org/en/download.html)
wget https://nginx.org/download/nginx-1.14.0.tar.gz
tar -zxf nginx-1.14.0.tar.gz
cd nginx-1.14.0

# configure 时,加入 Lua 相关编译参数
./configure  ... \
--with-ld-opt="-Wl,-rpath,$LUAJIT_LIB" \
--add-module=.../ngx_lua/ngx_devel_kit \
--add-module=.../ngx_lua/lua-nginx-module

# still make
make -j4
make install

example

编译完成后,你就可以写好配置文件然后启动 Nginx 了。关于 ngx_lua 的使用方式请参考 docs

接下来我举个 ngx_lua 的最简单例子:实现对 /admin.php 的访问请求返回 403 forbidden。

以上需求很简单,如果直接使用 Nginx location 的话:

    location = /admin.php {
        return 403;
    }

如果想要使用 Lua 实现,那么我们先把 Lua 代码写出来:

    if (ngx.var.request_uri == "/admin.php") then
        return ngx.exit(ngx.HTTP_FORBIDDEN)
    end

然后把它放进 access_by_lua_block 中:

    location / {
        access_by_lua_block {
            if (ngx.var.request_uri == "/admin.php") then
                return ngx.exit(ngx.HTTP_FORBIDDEN)
            end
        }
    }