OpenResty(nginx lua) 入门

在站点遇到攻击且无明显攻击特征,造成站点访问慢,nginx不断返回502等错误时,可利用nginx lua redis实现在指定的时间段内,若单IP的请求量达到指定的数量后对该IP进行封禁,nginx返回403禁止访问。利用redis的expire命令设置封禁IP的过期时间达到在指定的封禁时间后实行自动解封的目的。

OpenResty 官网:

一、安装环境:

OpenResty 是一个nginx和它的各种三方模块的一个打包而成的软件平台。最重要的一点是它将lua/luajit打包了进来,使得我们可以使用lua脚本来进行web的开发。有了lua,我们可以借助于nginx的异步非阻塞的功能,达到使用 lua 异步并发访问后端的 MySQL, PostgreSQL, Memcached, Redis等等服务。特别是特有的 ngx.location.capture_multi 功能让人印象深刻,其可以达到极大的减少浏览器的http连接数量,并且可以异步并发的访问后台 Java/PHP/Python 等等接口。OpenResty 架构的web可以轻松超越Node.js的性能,并且对后端语言没有限制,你可以使用Java/PHP/Python等等各种语言。OpenResty(nginx lua)可以替代node.js的前端渲染的功能。

  • CentOS x64 release 6.4(Final)
  • Nginx-1.4.1
  • Redis 2.6.14
  • LuaJIT-2.0.2

OpenResty (aka. ngx_openresty) is a full-fledged web application server by bundling the standard Nginx core, lots of 3rd-party Nginx modules, as well as most of their external dependencies.

二、安装步骤:

By taking advantage of various well-designed Nginx modules, OpenResty effectively turns the nginx server into a powerful web app server, in which the web developers can use the Lua programming language to script various existing nginx C modules and Lua modules and construct extremely high-performance web applications that are capable to handle 10K connections.

1、安装LuaJIT-2.0.2

OpenResty aims to run your server-side web app completely in the Nginx server, leveraging Nginx's event model to do non-blocking I/O not only with the HTTP clients, but also with remote backends like MySQL, PostgreSQL, Memcached, and Redis.

wget http://luajit.org/download/LuaJIT-2.0.2.tar.gz
tar -xzvf LuaJIT-2.0.2.tar.gz
cd LuaJIT-2.0.2
make && make install

1. 安装OpenResty

注:64位系统安装完成后或许还需要将/usr/local/lib/libluajit-5.1.so.2建立软连接到/lib64/ /libluajit-5.1.so.2,否则在后面nginx启动时会提示找不到依赖库。

先安装依赖:yum install readline-devel pcre-devel openssl-devel gcc

2、安装Redis 2.6.14

解压: tar zxvf ngx_openresty-1.9.3.1.tar.gz

wget http://redis.googlecode.com/files/redis-2.6.14.tar.gz
tar -xzvf redis-2.6.14.tar.gz
cd redis-2.6.14
make && make install

建立一个软连接:ln -s ngx_openresty-1.9.3.1 openresty

3、安装Nginx-1.4.1

进入目录:cd openresty

wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.21.tar.gz
wget http://www.openssl.org/source/openssl-1.0.1e.tar.gz
wget https://codeload.github.com/agentzh/echo-nginx-module/tar.gz/v0.45
wget https://codeload.github.com/chaoslawful/lua-nginx-module/tar.gz/v0.8.3
wget https://codeload.github.com/agentzh/redis2-nginx-module/tar.gz/v0.10
wget http://nginx.org/download/nginx-1.4.1.tar.gz
tar -xzvf pcre-8.21.tar.gz
tar -xzvf openssl-1.0.1e.tar.gz
tar -xzvf echo-nginx-module-0.45.tar.gz
tar -xzvf lua-nginx-module-0.8.3.tar.gz
tar -xzvf redis2-nginx-module-0.10.tar.gz
tar -xzvf nginx-1.4.1.tar.gz
cd nginx-1.4.1
./configure --prefix=/usr/local/nginx 
--sbin-path=/usr/local/nginx/nginx 
--user=www 
--group=www 
--with-poll_module 
--with-http_realip_module 
--with-http_addition_module 
--with-http_sub_module 
--with-http_image_filter_module 
--with-http_geoip_module 
--with-http_dav_module 
--with-http_flv_module 
--with-http_mp4_module 
--with-http_gunzip_module 
--with-http_gzip_static_module 
--with-http_random_index_module 
--with-http_secure_link_module 
--with-http_stub_status_module 
--with-pcre=/home/pcre-8.21 
--with-openssl=/home/openssl-1.0.1e 
--add-module=/home /echo-nginx-module-0.45 
--add-module=/home /lua-nginx-module-0.8.3 
--add-module=/home /redis2-nginx-module-0.10
make
make install

编译:

4、下载nginx中lua使用redis需要的依赖包redis.lua到nginx安装目录

./configure 
             --with-cc-opt="-I/usr/local/include" 
             --with-ld-opt="-L/usr/local/lib" 
             --prefix=/opt/openresty 

... ...
Configuration summary
    using system PCRE library
    using system OpenSSL library
    md5: using OpenSSL library
    sha1: using OpenSSL library
    using system zlib library

  nginx path prefix: "/opt/openresty/nginx"
  nginx binary file: "/opt/openresty/nginx/sbin/nginx"
  nginx configuration prefix: "/opt/openresty/nginx/conf"
  nginx configuration file: "/opt/openresty/nginx/conf/nginx.conf"
  nginx pid file: "/opt/openresty/nginx/logs/nginx.pid"
  nginx error log file: "/opt/openresty/nginx/logs/error.log"
  nginx http access log file: "/opt/openresty/nginx/logs/access.log"
  nginx http client request body temporary files: "client_body_temp"
  nginx http proxy temporary files: "proxy_temp"
  nginx http fastcgi temporary files: "fastcgi_temp"
  nginx http uwsgi temporary files: "uwsgi_temp"
  nginx http scgi temporary files: "scgi_temp"

其中 --prefix=/opt/openresty 指定了安装目录,不指定的话默认会安装到 /usr/local/openresty 目录下。``

5、将控制访问lua脚本access.lua放到nginx安装目录的conf目录下

编译安装: make && make install

ip_bind_time = 300  --封禁IP时间  
ip_time_out = 60    --指定ip访问频率时间段  
connect_count = 100 --指定ip访问频率计数最大值  
--连接redis  
local redis = require "resty.redis"  
local cache = redis.new()  
local ok , err = cache.connect(cache,"127.0.0.1","6379")  
cache:set_timeout(60000)  
--如果连接失败,跳转到脚本结尾  
if not ok then  
  goto A  
end  
--查询ip是否在封禁段内,若在则返回403错误代码  
--因封禁时间会大于ip记录时间,故此处不对ip时间key和计数key做处理  
is_bind , err = cache:get("bind_"..ngx.var.remote_addr)  
if is_bind == 1 then  
  ngx.exit(403)  
  goto A  
end  
start_time , err = cache:get("time_"..ngx.var.remote_addr)  
ip_count , err = cache:get("count_"..ngx.var.remote_addr)  
--如果ip记录时间大于指定时间间隔或者记录时间或者不存在ip时间key则重置时间key和计数key  
--如果ip时间key小于时间间隔,则ip计数 1,且如果ip计数大于ip频率计数,则设置ip的封禁key为1  
--同时设置封禁key的过期时间为封禁ip的时间  
if start_time == ngx.null or os.time() - start_time > ip_time_out then  
  res , err = cache:set("time_"..ngx.var.remote_addr , os.time())  
  res , err = cache:set("count_"..ngx.var.remote_addr , 1)  
else  
  ip_count = ip_count   1  
  res , err = cache:incr("count_"..ngx.var.remote_addr)  
  if ip_count >= connect_count then  
    res , err = cache:set("bind_"..ngx.var.remote_addr,1)  
    res , err = cache:expire("bind_",ip_bind_time)  
  end  
end  
--结尾标记  
::A::  
local ok, err = cache:close()  
[root@localhost src]# cd /opt/openresty/
[root@localhost openresty]# ls
bin  luajit  lualib  nginx

6、在nginx.conf文件的http段引入redis.lua包,加入代码:

可以看到 /opt/openresty 目录下四个文件夹,其中包括了 luajit,nginx。

lua_package_path"/usr/local/nginx/redis.lua;;";

启动openresty: /opt/openresty/nginx/sbin/nginx -c /opt/openresty/nginx/conf/nginx.conf -p /opt/openresty/nginx/

7、在nginx.conf中需要控制访问的站点location段中加入访问控制代码:

[root@localhost src]# ps -elf|grep nginx
1 S root      2076     1  0  80   0 - 34999 -      21:24 ?        00:00:00 nginx: master process /opt/openresty/nginx/sbin/nginx -c /opt/openresty/nginx/conf/nginx.conf -p /opt/openresty/nginx/
5 S nobody    2077  2076  0  80   0 - 35045 -      21:24 ?        00:00:00 nginx: worker process                                    
0 S root      2079  1678  0  80   0 -  1088 -      21:24 pts/1    00:00:00 grep nginx
access_by_lua_file/usr/local/nginx/conf/access.lua

验证可以访问: curl 127.0.0.1

现在可以启动redis和nginx进行测试了。

2. content_by_lua 和 content_太阳集团所有网址16877,by_lua_file

nginx 如何嵌入 lua 脚本。方法就是在nginx的配置文件nginx.conf 中使用 content_by_lua 或者 cotent_by_lua_file 指令:

1) content_by_lua 一般在很简单的lua脚本时使用:

        location /lua {
                set $test "hello, world.";
                content_by_lua '
                        ngx.header.content_type = "text/plain";
                        ngx.say(ngx.var.test);
                ';
        }

访问 可以看到输出到页面的  hello, world.

2)cotent_by_lua_file 适应于复杂的 lua 脚本,专门放入一个文件中:

        location /lua2 {
            #lua_code_cache off;
            content_by_lua_file lua/hello.lua;
        }

路径相对于 /opt/openresty/nginx

[root@localhost lua]# pwd
/opt/openresty/nginx/lua
[root@localhost lua]# cat hello.lua
ngx.say('hello ngx_lua!!!!');

本例子中 hello.lua 只包含一句: ngx.say('hello ngx_lua!!!!');

访问 /lua2 :

[root@localhost lua]# curl localhost/lua
hello ngx_lua!!!!

可以看到访问成功。

在 nginx.conf 文件的 server {.. ...} 中加入 lua_code_cache off; 可以方便调试lua脚本,修改lua脚本之后,不需要 reload nginx.

openresty 中的 nginx 嵌入 luajit 的原理:

太阳集团所有网址16877 1

每一个nginx的进程中都嵌入了一个 luajit的虚拟机,来执行lua脚本。nginx将lua脚本的执行交给了luajit vm.

3. ngx_lua 的指令 和 API

上面我们说到 nginx 嵌入 lua 脚本可以使用 content_by_lua 和 content_by_lua_file,它们其实是指令(Directives),类似的指令还有很多,

具体参见:

太阳集团所有网址16877 2

这些指令都是 nginx 访问 lua 脚本的入口。

ngx_lua API:

指令是 nginx 访问 lua 脚本的入口。那么lua脚本如何调用nginx中的函数呢?就是通过 ngx_lua 的API 。

具体介绍参见:

The various *_by_lua and *_by_lua_file configuration directives serve as gateways to the Lua API within the nginx.conf file. The NGINX Lua API described below can only be called within the user Lua code run in the context of these configuration directives.

The API is exposed to Lua in the form of two standard packages ngx and ndk. These packages are in the default global scope within ngx_lua and are always available within ngx_lua directives.

太阳集团所有网址16877 3

其实nginx和Lua的交互开发主要就是指令和API,当然还有lua脚本的语法。指令是nginx访问lua的入口,API是lua调用nginx的函数,lua是脚本编程语言。

指令其实很简单,所以主要就是熟悉ngx_lua的 API 和Lua语法。

4. lua 访问 redis

lua-resty-redis 模块: (有文档可以参考)

在nginx.conf中加入:

        location /redis_test{
            content_by_lua_file lua/redis_test.lua;
        }

redis_test.lua 内容:

[root@localhost lua]# cat redis_test.lua
local redis = require "resty.redis"
local red = redis:new()

red:set_timeout(1000)

local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
        ngx.say("failed to connect: ", err)
        return
end

ngx.say("set result: ", ok)

local res, err = red:get("dog")
if not res then
        ngx.say("failed to get doy: ", err)
        return
end

if res == ngx.null then
        ngx.say("dog not found.")
        return
end

ngx.say("dog: ", res)

[root@localhost lua]#

访问:

[root@localhost lua]# curl localhost/redis_test
set result: 1
dog: an animal
[root@localhost lua]#

我们看到访问成功。

5. lua 访问mysql

openresty的mysql模块:lua-resty-mysql :

在nginx.conf加入如下配置:

本文由太阳集团所有网址16877发布于太阳集团城网址送彩金,转载请注明出处:OpenResty(nginx lua) 入门

您可能还会对下面的文章感兴趣: