kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp

nginx解决sql注入

https://blog.csdn.net/A_Apprentice/article/details/125861741

  1. get请求好处理

  2. post请求 由于需要拿到请求体,需要安装lua插件支持

errlog

1
2
3
ngx.log(ngx.ERR, "error: ", body)

tail -f /var/log/nginx/error.log

当前方案 :

get在server级别处理

post在lication级别处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	# 文件上传的限制
	client_max_body_size 100m;

	if ($query_string ~* ".*('|--|union|insert|drop|truncate|update|(%20)from|grant|(%20)where|(%20)select|(%20)and|(%20)chr|(%20)mid|like|(%20)iframe|(%20)script|alert|webscan|dbappsecurity|style|WAITFOR|confirm|innerhtml|innertext|class).*") { return 403; }
        #if ($uri ~* (.*)(insert|select|delete|update|count|master|truncate|declare|\*|%|\')(.*)$ ) { return 403; }
        if ($http_user_agent ~ ApacheBench|WebBench|Jmeter|JoeDog|Havij|GetRight|TurnitinBot|GrabNet|masscan|mail2000|github|wget|curl) { return 444; }
        if ($http_user_agent ~ "Go-Ahead-Got-It") { return 444; }
        if ($http_user_agent ~ "GetWeb!") { return 444; }
        if ($http_user_agent ~ "Go!Zilla") { return 444; }
        if ($http_user_agent ~ "Download Demon") { return 444; }
        if ($http_user_agent ~ "Indy Library") { return 444; }
        if ($http_user_agent ~ "libwww-perl") { return 444; }
        if ($http_user_agent ~ "Nmap Scripting Engine") { return 444; }
        if ($http_user_agent ~ "Load Impact") { return 444; }
        if ($http_user_agent ~ "~17ce.com") { return 444; }
        if ($http_user_agent ~ "WebBench*") { return 444; }
        if ($http_referer ~* 17ce.com) { return 444; }
        if ($http_user_agent ~* qiyunce) { return 444; }
        if ($http_user_agent ~* YunGuanCe) { return 403; }
        if ($http_referer ~* WebBench*") { return 444; }
        if ($http_user_agent ~ "BLEXBot") { return 403; }
        if ($http_user_agent ~ "MJ12bot") { return 403; }
        if ($http_user_agent ~ "semalt.com") { return 403; }
        if ($http_user_agent ~ "sqlmap") { return 403; }

        #自动防护
	if ($request_uri ~* \.(htm|do)\?(.*)$) {
            set $req $2;
        }
        if ($req ~* "(cost\()|(concat\()") {
            return 503;
        }
        if ($req ~* "union[+|(%20)]") {
            return 503;
        }
        if ($req ~* "and[+|(%20)]") {
            return 503;
        }
        if ($req ~* "select[+|(%20)]") {
            return 503;
        }


        #溢出过滤
        if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 403; }
        if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
        if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 403; }
        if ($query_string ~ "proc/self/environ") { return 403; }
        if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") { return 403; }
        if ($query_string ~ "base64_(en|de)code\(.*\)") { return 403; }

        #文件注入禁止
        if ($query_string ~ "[a-zA-Z0-9_]=http://") { return 403; }
        if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") { return 403; }
        if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") { return 403; }

        location / {

            lua_need_request_body on;
            access_by_lua_block {
                local body = ngx.var.request_body
                if ngx.var.request_method == "POST" and body ~= nil then
                    local regex0 = "(.*?((sqlwhere)|(c0-param0)).*?){1,}"
                    local m0 = ngx.re.match(body, regex0, "i")
                    local regex1 = "(.*?((insert)|(drop)|(truncate)|(update)|(grant)|(chr)|(webscan)|(dbappsecurity)|(WAITFOR)).*?){1,}"
                    local m1 = ngx.re.match(body, regex1, "i")
                    local regex2 = "(.*?((union)|(insert)|(drop)|(truncate)|(grant)|(chr)|(iframe)|(alert)|(webscan)|(dbappsecurity)|(style)|(WAITFOR)|(confirm)|(innerhtml)|(innertext)|(class)).*?){1,}"
                    local m2 = ngx.re.match(body, regex2, "i")
                    if (m0 and m1) or (not m0 and m2) then
                        ngx.log(ngx.ERR, "error: ", body)
                        ngx.status = 403
                        ngx.say('{"code": 403, "msg": "非法参数","ok": false,"runningTime": "0ms"}')
                    end
                end

                ngx.req.read_body()
                local args, err = ngx.req.get_post_args()
                if args then
                    for k, v in pairs(args) do
                       if k == "j_username" or k == "j_password" then
                           local regex = "(.*?((union)|(insert)|(drop)|(truncate)|(update)|(from)|(grant)|(where)|(select)|(chr)|(mid)|(like)|(iframe)|(script)|(alert)|(webscan)|(dbappsecurity)|(style)|(WAITFOR)|(confirm)|(innerhtml)|(innertext)|(class)).*?){1,}"
                           local m = ngx.re.match(v, regex, "i")
                           if m then
                              ngx.log(ngx.ERR, "error: ", v)
                              ngx.status = 403
                              ngx.say('{"code": 403, "msg": "非法参数","ok": false,"runningTime": "0ms"}')
                           end
                       end
                   end
                end
            }


            proxy_http_version 1.1;
            proxy_set_header Connection "";

            proxy_next_upstream http_502 error timeout invalid_header;
            proxy_pass http://192.168.100.199:8888;
            proxy_set_header Host $http_host;

            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        #自动防护
	if ($request_uri ~* \.(htm|do)\?(.*)$) {
            set $req $2;
        }
        if ($req ~* "(cost\()|(concat\()") {
            return 503;
        }
        if ($req ~* "union[+|(%20)]") {
            return 503;
        }
        if ($req ~* "and[+|(%20)]") {
            return 503;
        }
        if ($req ~* "select[+|(%20)]") {
            return 503;
        }

1、这里之所以使用$request_uri而未使用$query_string变量,因为通过$request_uri进行rewrite分割更精准。

2、%20代表的是空格,同上文不的是,我这里把上面的空格匹配进行了取消。这样像www.361way.com/aaa.do?select * from test之样的也可以进行匹配。

3、上面的htm是伪静态,实际上同.do一样,也是动态文件。为了便于和静态文件进行区分,这里选择了htm而不是html。

4、注意,最上面的url里面的\? ,这个也分重要。如果没有的话,www.361way.com/aaa.htm select * from test不会被过滤,而www.361way.com/aaa.htm?select * from test会被过滤。如果想将前面的也过滤,只需要把\? 取消即可。

https://blog.csdn.net/remotesupport/article/details/11967851

https://blog.csdn.net/qq_34777982/article/details/125390989

http://www.3qphp.com/linux/centos/2581.html

lua-nginx-module的所有指令以及所有方法

http://www.04007.cn/article/430.html

在使用lua时,也许我们很多时候都只用了它几个基础的方法:比如http://www.04007.cn/article/129.html 这里面的content_by_lua,或者content_by_lua_file方法。在nginx+lua的脚本中,我们常用的ngx.say,以及ngx.log等,但实际ngx.还有很多好用的方法。

lua_nginx_module中可使用的指令列表:

指令名称说明
lua_use_default_type是否使用default_type指令定义的Content-Type默认值
lua_code_cache*_by_lua_file文件是否cache
lua_regex_cache_max_entries 
lua_regex_match_limit 
lua_package_path用Lua写的lua外部库路径(.lua文件)
lua_package_cpath用C写的lua外部库路径(.so文件)
init_by_luamaster进程启动时挂载的lua代码
init_by_lua_file 
init_worker_by_luaworker进程启动时挂载的lua代码,常用来执行一些定时器任务
init_worker_by_lua_file 
set_by_lua设置变量
set_by_lua_file 
content_by_luahandler模块
content_by_lua_file 
rewrite_by_lua 
rewrite_by_lua_file 
access_by_lua 
access_by_lua_file 
header_filter_by_luaheader filter模块
header_filter_by_lua_file 
body_filter_by_luabody filter模块,ngx.arg[1]代表输入的chunk,ngx.arg[2]代表当前chunk是否为last
body_filter_by_lua_file 
log_by_lua 
log_by_lua_file 
lua_need_request_body是否读请求体,跟ngx.req.read_body()函数作用类似
lua_shared_dict创建全局共享的table(多个worker进程共享)
lua_socket_connect_timeoutTCP/unix 域socket对象connect方法的超时时间
lua_socket_send_timeoutTCP/unix 域socket对象send方法的超时时间
lua_socket_send_lowat设置cosocket send buffer的low water值
lua_socket_read_timeoutTCP/unix 域socket对象receive方法的超时时间
lua_socket_buffer_sizecosocket读buffer大小
lua_socket_pool_sizecosocket连接池大小
lua_socket_keepalive_timeoutcosocket长连接超时时间
lua_socket_log_errors是否打开cosocket错误日志
lua_ssl_ciphers 
lua_ssl_crl 
lua_ssl_protocols 
lua_ssl_trusted_certificate 
lua_ssl_verify_depth 
lua_http10_buffering 
rewrite_by_lua_no_postpone 
lua_transform_underscores_in_response_headers 
lua_check_client_abort是否监视client提前关闭请求的事件,如果打开监视,会调用ngx.on_abort()注册的回调
lua_max_pending_timers 
lua_max_running_timers 

在lua程序脚本中可使用的操作方法及可取得的变量和常量列表

操作指令说明
ngx.arg指令参数,如跟在content_by_lua_file后面的参数
ngx.var变量,ngx.var.VARIABLE引用某个变量
ngx.ctx请求的lua上下文
ngx.header响应头,ngx.header.HEADER引用某个头
ngx.status响应码
API说明
ngx.log输出到error.log
print等价于 ngx.log(ngx.NOTICE, ...)
ngx.send_headers发送响应头
ngx.headers_sent响应头是否已发送
ngx.resp.get_headers获取响应头
ngx.timer.at注册定时器事件
ngx.is_subrequest当前请求是否是子请求
ngx.location.capture发布一个子请求
ngx.location.capture_multi发布多个子请求
ngx.exec 
ngx.redirect 
ngx.print输出响应
ngx.say输出响应,自动添加'\n'
ngx.flush刷新响应
ngx.exit结束请求
ngx.eof 
ngx.sleep无阻塞的休眠(使用定时器实现)
ngx.get_phase 
ngx.on_abort注册client断开请求时的回调函数
ndk.set_var.DIRECTIVE 
ngx.req.start_time请求的开始时间
ngx.req.http_version请求的HTTP版本号
ngx.req.raw_header请求头(包括请求行)
ngx.req.get_method请求方法
ngx.req.set_method请求方法重载
ngx.req.set_uri请求URL重写
ngx.req.set_uri_args 
ngx.req.get_uri_args获取请求参数
ngx.req.get_post_args获取请求表单
ngx.req.get_headers获取请求头
ngx.req.set_header 
ngx.req.clear_header 
ngx.req.read_body读取请求体
ngx.req.discard_body扔掉请求体
ngx.req.get_body_data 
ngx.req.get_body_file 
ngx.req.set_body_data 
ngx.req.set_body_file 
ngx.req.init_body 
ngx.req.append_body 
ngx.req.finish_body 
ngx.req.socket 
ngx.escape_uri字符串的url编码
ngx.unescape_uri字符串url解码
ngx.encode_args将table编码为一个参数字符串
ngx.decode_args将参数字符串编码为一个table
ngx.encode_base64字符串的base64编码
ngx.decode_base64字符串的base64解码
ngx.crc32_short字符串的crs32_short哈希
ngx.crc32_long字符串的crs32_long哈希
ngx.hmac_sha1字符串的hmac_sha1哈希
ngx.md5返回16进制MD5
ngx.md5_bin返回2进制MD5
ngx.sha1_bin返回2进制sha1哈希值
ngx.quote_sql_strSQL语句转义
ngx.today返回当前日期
ngx.time返回UNIX时间戳
ngx.now返回当前时间
ngx.update_time刷新时间后再返回
ngx.localtime 
ngx.utctime 
ngx.cookie_time返回的时间可用于cookie值
ngx.http_time返回的时间可用于HTTP头
ngx.parse_http_time解析HTTP头的时间
ngx.re.match 
ngx.re.find 
ngx.re.gmatch 
ngx.re.sub 
ngx.re.gsub 
ngx.shared.DICT 
ngx.shared.DICT.get 
ngx.shared.DICT.get_stale 
ngx.shared.DICT.set 
ngx.shared.DICT.safe_set 
ngx.shared.DICT.add 
ngx.shared.DICT.safe_add 
ngx.shared.DICT.replace 
ngx.shared.DICT.delete 
ngx.shared.DICT.incr 
ngx.shared.DICT.flush_all 
ngx.shared.DICT.flush_expired 
ngx.shared.DICT.get_keys 
ngx.socket.udp 
udpsock:setpeername 
udpsock:send 
udpsock:receive 
udpsock:close 
udpsock:settimeout 
ngx.socket.tcp 
tcpsock:connect 
tcpsock:sslhandshake 
tcpsock:send 
tcpsock:receive 
tcpsock:receiveuntil 
tcpsock:close 
tcpsock:settimeout 
tcpsock:setoption 
tcpsock:setkeepalive 
tcpsock:getreusedtimes 
ngx.socket.connect 
ngx.thread.spawn 
ngx.thread.wait 
ngx.thread.kill 
coroutine.create 
coroutine.resume 
coroutine.yield 
coroutine.wrap 
coroutine.running 
coroutine.status 
ngx.config.debug编译时是否有 --with-debug选项
ngx.config.prefix编译时的 --prefix选项
ngx.config.nginx_version返回nginx版本号
ngx.config.nginx_configure返回编译时 ./configure的命令行选项
ngx.config.ngx_lua_version返回ngx_lua模块版本号
ngx.worker.exiting当前worker进程是否正在关闭(如reload、shutdown期间)
ngx.worker.pid返回当前worker进程的pid
  
常量说明
Core constantsngx.OK (0)
ngx.ERROR (-1)
ngx.AGAIN (-2)
ngx.DONE (-4)
ngx.DECLINED (-5)
ngx.nil
HTTP method constantsngx.HTTP_GET
ngx.HTTP_HEAD
ngx.HTTP_PUT
ngx.HTTP_POST
ngx.HTTP_DELETE
ngx.HTTP_OPTIONS  
ngx.HTTP_MKCOL    
ngx.HTTP_COPY      
ngx.HTTP_MOVE     
ngx.HTTP_PROPFIND 
ngx.HTTP_PROPPATCH 
ngx.HTTP_LOCK 
ngx.HTTP_UNLOCK    
ngx.HTTP_PATCH   
ngx.HTTP_TRACE  
HTTP status constantsngx.HTTP_OK (200)
ngx.HTTP_CREATED (201)
ngx.HTTP_SPECIAL_RESPONSE (300)
ngx.HTTP_MOVED_PERMANENTLY (301)
ngx.HTTP_MOVED_TEMPORARILY (302)
ngx.HTTP_SEE_OTHER (303)
ngx.HTTP_NOT_MODIFIED (304)
ngx.HTTP_BAD_REQUEST (400)
ngx.HTTP_UNAUTHORIZED (401)
ngx.HTTP_FORBIDDEN (403)
ngx.HTTP_NOT_FOUND (404)
ngx.HTTP_NOT_ALLOWED (405)
ngx.HTTP_GONE (410)
ngx.HTTP_INTERNAL_SERVER_ERROR (500)
ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
ngx.HTTP_SERVICE_UNAVAILABLE (503)
ngx.HTTP_GATEWAY_TIMEOUT (504) 
Nginx log level constantsngx.STDERR
ngx.EMERG
ngx.ALERT
ngx.CRIT
ngx.ERR
ngx.WARN
ngx.NOTICE
ngx.INFO
ngx.DEBUG

Lua-Nginx-Module常用指令

https://blog.51cto.com/xikder/2331336

https://blog.51cto.com/xikder/2331368

https://blog.51cto.com/xikder/2331504

本章将会讲解基于LuaJIT的Lua-Nginx-Module,它作为Nginx的第三方开源软件,拥有十分丰富的功能,可以轻松完成高并发的业务需求。

注意:本书使用的Lua-Nginx-Module版本是0.10.13。Nginx API for Lua将被简称为Lua API,而Lua-Nginx-Module则被简称为Ngx_lua。后面章节中涉及到的Lua API大部分是包含参数的,如果参数以?结尾,代表这个参数是可选的,如在指令ngx.req.get_headers (max_headers?, raw?)中,max_headers和raw是可选的。

一、Nginx和OpenResty

首先,来认识一下OpenResty,它是一个基于Nginx和Lua开发的高性能的Web平台,包含大量成熟的第三方库,可快速搭建出高性能的Web服务器,支持常用的反向代理、网关系统、Web应用等。

如果在Nginx上使用Ngx_lua,需要先进行编译;而OpenResty已经包含此模块,不需要再进行编译了。读者可以自由选择使用Nginx或OpenResty来搭建服务,如果无法抉择,可参考如下场景。

使用Nginx编译Ngx_Lua的场景

HTTP代理服务器:复杂度较小,只需部分组件即可,且代理服务器一般由运维人员进行维护。使用Nginx的稳定版进行编译,在性能方面会更有保障,而OpenResty是Nginx的主线版,可能会不定期更新。

OpenResty的使用场景

API服务:业务需求多,需要大量组件。
网关系统:需要大量组件和指令来实现动态组件功能。
Web应用服务器:业务服务、页面服务等,如详情页业务的开发。
使用Nginx编写的Lua代码都可以直接迁移到OpenResty上;反之却不一定可行,毕竟OpenResty的组件更多。

二、安装Ngx_lua

请先安装LuaJIT 2.1.0-beta3(详见第6.2节)并需要编译ngx_devel_kit模块。 下面是在Nginx上的安装方式(OpenResty自带此模块,不必安装编译):

1
2
3
4
5
6
7
8
9
10
11
# wget 'http://nginx.org/download/nginx-1.12.2.tar.gz'
# git clone https://github.com/simplresty/ngx_devel_kit.git
# git clone https://github.com/openresty/lua-nginx-module.git
# tar -xzvf nginx-1.12.2.tar.gz
# cd nginx-1.12.2/
# ./configure --prefix=/usr/local/nginx_1.12.2 \
     --add-module=../ngx_devel_kit \
     --add-module=../lua-nginx-module
     --with-ld-opt="-Wl,-rpath,$LUAJIT_LIB"

# make && make install

并不是每个Nginx版本都支持最新的Ngx_lua,目前已知支持最新Ngx_lua的Nginx版本如下:

1
2
3
4
5
6
7
8
1.13.x (last tested: 1.13.6)
1.12.x
1.11.x (last tested: 1.11.2)
1.10.x
1.9.x (last tested: 1.9.15)
1.8.x
1.7.x (last tested: 1.7.10)
1.6.x

如需获取最新版本的支持动态,请参考https://github.com/openresty/lua-nginx-module# nginx-compatibility。

三、牢记context标识

Ngx_lua API指令和Nginx的指令一样,都存在配置环境的约束问题,因此在使用过程中要确保指令的环境符合预期,例如:

1
2
3
4
ngx.var.VARIABLE
语法:ngx.var.VAR_NAME
context(配置环境):set_by_lua*,rewrite_by_lua*,access_by_lua*,content_by_lua*,header_ filter_by_lua*,body_filter_by_lua*,log_by_lua*
context即配置环境,第一次接触Ngx_lua的读者看到这样的配置环境可能会觉得难以理解,因为这还涉及到Ngx_Lua的执行阶段(后面会有介绍)。

四、Hello world

首先,还是来一条经典语句“Hello, world”,在Nginx配置中加入一个server:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
    listen       80;
    server_name  testnginx.com;
    charset koi8-r;
    location = /test {
     #设置文件使用的默认MIME-type,将会增加一个Content-Type:text/plain的响应头
     default_type 'text/plain';    
     -- content_by_lua_block执行阶段
     content_by_lua_block {    
         ngx.say('Hello,world!')
     }
    }
}

访问这个server,输出如下:

1
2
#  curl -I http://testnginx.com/test
Hello,world!    

ngx.say将数据作为响应体输出,返回给客户端,并在末尾加上一个回车符。

代码中用到了content_by_lua_block这个指令块,它的主要作用是在HTTP的内容处理阶段生成数据,详见第8.6节。

Nginx Openresty - 读取请求体

https://blog.csdn.net/trustnature/article/details/94417336

由于nginx默认不读取请求体的数据,因此当 Lua 通过 ngx.var.request_body 的方式获取请求体时会发现数据为空,那么,该如何获得请求体的数据呢?

方式一:lua_need_request_body

1
2
3
4
5
语法:lua_need_request_body<on|off>

默认值:off

环境:http、server、location、

含义:默认为off,即不读取请求体。如果设置为on,则表示强制读取请求体,此时,可以通过 ngx.var.request_body 来获取请求体的数据。但需要注意一种情况,$request_body 存在与内存中,如果它的字节大小超过Nginx配置的 client_body_buffer_size 的值,Nginx就会把请求体存放到临时文件中。此时数据就不存在与内存中了,这会导致 $request_body 为空,所以需要设置 client_body_buffer_size 和 client_max_body_size 的值相同,避免出现这种情况。

这种配置方式不够灵活,Ngx_Lua官网也不推荐使用此方法。

方式二:ngx.req.read_body

1
2
3
语法:ngx.req.read_body()

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*

含义:同步读取客户端请求体,且不会阻塞Nginx的事件循环。使用此指令后,就可以通过 ngx.req.get_body_data 来获取请求体的数据了。按如果使用临时文件来存放请求体,就需要先使用函数 ngx.req.get_body_file 来获取临时文件名,再读取临时文件中的请求体数据。

1
2
3
4
5
指令:ngx.req.get_body_data

语法:data = ngx.req.get_body_data()

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*、log_by_lua*

含义:执行 ngx.req.read_body 指令后,可以使用本指令在内存中获取请求体数据,结果会返回一个Lua的字符串类型数据。如果要获取Lua的table类型的数据,则需要使用 ngx.req.get_post_args

1
2
3
4
5
指令:ngx.req.get_post_data

语法:args,err=ngx.req.get_post_args(max_args?)

环境:rewrite_by_lua*、access_by_lua*、content_by_lua*、header_filter_by_lua*、body_filter_by_lua*、log_by_lua*

含义:在执行 ngx.req.read_body 指令后,可以使用本指令读取包含当前请求在内的所有POST值请求的查询参数,返回一个Lua的table类型的数据。max_args 参数的作用时限制参数的数量。为了服务的安全,最多支持使用100个参数(包括重复的参数),超过限制的参数会被忽略。如果max_args为0,则表示关闭此限制;但为了避免被无穷多的参数攻击,不要将max_args设置为0,如果最多支持使用10个参数,则应配置为 ngx.req.get_post_args(10)。

使用场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
content_by_lua_block {
	local ngx = require "ngx"
	ngx.req.read_body()
	local data = ngx.req.get_body_data()
	if data then
		ngx.print('ngx.req.get_body_data:',data,')
		return
	else
		lcoal file = ngx.req.get_body_file()
		if file then
			ngx.say("body is in file",file)
		else
			ngx.say("no body found")
		end
	end
}

Nginx 安装 Lua 支持

Nginx 支持 Lua 需要安装 lua-nginx-module 模块,一般常用有 2 种方法:

编译 Nginx 的时候带上 lua-nginx-module 模块一起编译

使用 OpenResty: Nginx + 一些模块,默认启用了 Lua 支持(推荐使用此方式)


OpenResty is just an enhanced version of Nginx by means of addon modules anyway. You can take advantage of all the exisitng goodies in the Nginx world.

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

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

OpenResty

OpenResty 的安装很方便,对于一些常见的 Linux 发行版本,OpenResty® 提供 官方预编译包,CentOS 使用 yum,Ubuntu 使用 apt-get,具体请参考 https://openresty.org/cn/installation.html%EF%BC%8C%E4%BB%A5%E4%B8%8B%E4%BB%A5CentOS 7 中安装 OpenResty 为例。

CentOS 7 使用 OpenResty

终端执行下面 3 条命令把 OpenResty 安装到 /usr/local/openresty

1
2
3
4
5
sudo yum install yum-utils

sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

sudo yum install openresty

Nginx 的配置文件位于 /usr/local/openresty/nginx/conf/nginx.conf (openresty -V 中没有指定)

验证

/usr/local/nginx/conf/nginx.conf 中添加 Lua 测试代码

1
2
3
4
location /lua {
	default_type 'text/html';
	content_by_lua 'ngx.say("hello world");';
}

启动 openresty

1
openresty

curl http://localhost/lua 输出 hello world 则说明 Nginx 支持 Lua

help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost ~]# openresty -h
nginx version: openresty/1.21.4.1
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
             [-e filename] [-c filename] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/local/openresty/nginx/)
  -e filename   : set error log file (default: logs/error.log)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file

编译 Nginx + Lua

编译 Nginx 需要先准备好下面的这些工具,如果不确定是否已安装,可以在编译的时候根据出现的错误提示再进行安装

1
2
yum install -y gcc g++ gcc-c++
yum -y install zlib zlib-devel openssl openssl--devel pcre pcre-devel

Nginx 支持 Lua 需要依赖 LuaJIT-2.0.4.tar.gz,ngx_devel_kit,lua-nginx-module,下面介绍具体的编译过程 (都下载到 /root 目录)

下载安装 LuaJIT-2.0.4.tar.gz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
wget -c http://luajit.org/download/LuaJIT-2.0.4.tar.gz
tar xzvf LuaJIT-2.0.4.tar.gz
cd LuaJIT-2.0.4
make install PREFIX=/usr/local/luajit

# 添加环境变量
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0

下载解压 ngx_devel_kit

wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
tar -xzvf v0.3.0.tar.gz

下载解压 lua-nginx-module
wget https://github.com/openresty/lua-nginx-module/archive/v0.10.8.tar.gz
tar -xzvf v0.10.8.tar.gz

下载安装 nginx-1.10.3.tar.gz

wget http://nginx.org/download/nginx-1.10.3.tar.gz
tar -xzvf nginx-1.10.3.tar.gz
cd nginx-1.10.3

# 注意ngx_devel_kit和lua-nginx-module 以实际解压路径为准
./configure --add-module=/root/ngx_devel_kit-0.3.0 --add-module=/root/lua-nginx-module-0.10.8

make -j2
make install

支持 Nginx 被安装到了 /usr/local/nginx,配置文件为 /usr/local/nginx/conf/nginx.conf

验证

将 nginx 做成命令: ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

/usr/local/nginx/conf/nginx.conf 中添加 Lua 测试代码

1
2
3
4
location /lua {
	default_type 'text/html';
	content_by_lua 'ngx.say("hello world");';
}

启动 openresty

1
openresty

curl http://localhost/lua 输出 hello world 则说明 Nginx 支持 Lua

上面编译 Nginx 的内容来源于 http://www.cnblogs.com/aoeiuv/p/6856056.html%EF%BC%8C%E7%BC%96%E8%AF%91 Nginx 相对使用 OpenResty 麻烦一些,不过也不难,根据自己的喜好选择即可。

http://qtdebug.com/mac-nginx-lua/