nginx+lua+redis 限制ip的访问次数

原文 地址:
https://www.superman2014.com/2015/08/30/nginxluaredis-%E9%99%90%E5%88%B6ip%E7%9A%84%E8%AE%BF%E9%97%AE%E6%AC%A1%E6%95%B0/

一、安装环境:

  • 阿里云centos 6.5
  • Nginx-1.4.4
  • Redis 3.0.3
  • LuaJIT-2.0.2

二、安装步骤:

1、安装LuaJIT-2.0.2

 

1

2

3

4

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

 

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

2.redis安装过程

 

1

2

3

4

$ wget http://download.redis.io/releases/redis-3.0.3.tar.gz

$ tar xzf redis-3.0.3.tar.gz

$ cd redis-3.0.3

$ make

3. nginx1.4.4的安装

 

1

2

3

4

5

6

7

8

9

10

11

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

 

tar -xzvf lua-nginx-module-0.8.3.tar.gz

tar -xzvf redis2-nginx-module-0.10.tar.gz

 

wget http://nginx.org/download/nginx-1.4.4.tar.gz

 

 

./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_sub_module --with-http_gzip_static_module --with-http_stub_status_module --with-pcre --with-http_realip_module   --with-http_gzip_static_module  --add-module=redis2-nginx-module-0.10   --add-module=lua-nginx-module-0.8.3 && make && make install

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

https://codeload.github.com/agentzh/lua-resty-redis/tar.gz/v0.15

5. 修改nginx.conf文件

 

nginx+lua+redis 限制ip的访问次数_第1张图片

test.lua内容如下:

 

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

$ cat /usr/local/nginx/test.lua

 

local redis = require "resty.redis"

local red = redis:new()

 

red:set_timeout(1000) -- 1 sec

 

-- or connect to a unix domain socket file listened

-- by a redis server:

--     local ok, err = red:connect("unix:/path/to/redis.sock")

 

local ok, err = red:connect("127.0.0.1", 6379)

if not ok then

    ngx.say("failed to connect: ", err)

    return

end

 

ok, err = red:set("dog", "an aniaml")

if not ok then

    ngx.say("failed to set dog: ", err)

    return

end

 

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

 

local res, err = red:get("dog")

if not res then

    ngx.say("failed to get dog: ", err)

    return

end

 

if res == ngx.null then

    ngx.say("dog not found.")

    return

end

 

ngx.say("dog: ", res)

 

red:init_pipeline()

red:set("cat", "Marry")

red:set("horse", "Bob")

red:get("cat")

red:get("horse")

local results, err = red:commit_pipeline()

if not results then

    ngx.say("failed to commit the pipelined requests: ", err)

    return

end

 

for i, res in ipairs(results) do

    if type(res) == "table" then

    if not res[1] then

        ngx.say("failed to run command ", i, ": ", res[2])

    else

        -- process the table value

    end

    else

    -- process the scalar value

    end

end

 

-- put it into the connection pool of size 100,

-- with 0 idle timeout

local ok, err = red:set_keepalive(0, 100)

if not ok then

    ngx.say("failed to set keepalive: ", err)

    return

end

 

-- or just close the connection right away:

-- local ok, err = red:close()

-- if not ok then

--     ngx.say("failed to close: ", err)

--     return

-- end

6. ip限制access.lua

 

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

$ cat /usr/local/nginx/access.lua

ip_bind_time = 600  --封禁IP时间

ip_time_out = 30    --指定ip访问频率时间段

connect_count = 50 --指定ip访问频率计数最大值

 

--连接redis

local redis = require "resty.redis"

local red = redis:new()

local ok, err = red:connect("127.0.0.1", 6379)

red:set_timeout(1000) -- 1 sec

 

--如果连接失败,跳转到脚本结尾

if not ok then

    goto A

end

 

--

--查询ip是否在封禁段内,若在则返回403错误代码

--因封禁时间会大于ip记录时间,故此处不对ip时间key和计数key做处理

is_bind, err = red:get("bind:"..ngx.var.remote_addr)

if is_bind == '1' then

    ngx.exit(403)

    goto A

end

 

--如果ip记录时间大于指定时间间隔或者记录时间或者不存在ip时间key则重置时间key和计数key

--如果ip时间key小于时间间隔,则ip计数+1,且如果ip计数大于ip频率计数,则设置ip的封禁key为1

--同时设置封禁key的过期时间为封禁ip的时间

start_time, err = red:get("time:"..ngx.var.remote_addr)

ip_count, err = red:get("count:"..ngx.var.remote_addr)

 

if start_time == ngx.null or os.time() - start_time > ip_time_out then

    res, err = red:set("time:"..ngx.var.remote_addr , os.time())

    res, err = red:set("count:"..ngx.var.remote_addr , 1)

else

    ip_count = ip_count + 1

    res, err = red:incr("count:"..ngx.var.remote_addr)

    if ip_count >= connect_count then

        res, err = red:set("bind:"..ngx.var.remote_addr, 1)

        res, err = red:expire("bind:"..ngx.var.remote_addr, ip_bind_time)

    end

end

 

-- 结束标记

::A::

local ok, err = red:close()

 

7.新的nginx.conf配置如下:

 

1

2

3

4

5

6

location ~ \.php$ {

        access_by_lua_file /usr/local/nginx/access.lua;

 

        include fastcgi.conf;

        fastcgi_pass 127.0.0.1:9000;

}

8.访问记录,在redis内的截图:

 

nginx+lua+redis 限制ip的访问次数_第2张图片

 

9.访问次数过多,返回结果:

 

nginx+lua+redis 限制ip的访问次数_第3张图片

 

原文 地址:
https://www.superman2014.com/2015/08/30/nginxluaredis-%E9%99%90%E5%88%B6ip%E7%9A%84%E8%AE%BF%E9%97%AE%E6%AC%A1%E6%95%B0/

你可能感兴趣的:(nginx+lua+redis 限制ip的访问次数)