2

My goal is to prevent the high frequent request based on user IP, and i google the openresty and found it can be played with Lua. So i wrote the following script, i'm a newbie to Lua, could anyone give me some advice on this script, or even correct me.

this script is to block request which requests over 3 times in 100s

local limit_request_times = 3
local expire_time = 100

local user_ip = ngx.var.remote_addr

-- ngx.say("user_ip: ", user_ip)

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


local res, err = red:get(user_ip)
if res == ngx.null then
    ngx.say("no request record, add this user_ip to redis")
    ok, err = red:set(user_ip, 1)
    if not ok then
        -- ngx.say("add user_ip failed")
        ngx.exit(ngx.HTTP_FORBIDDEN)
        return
    else
        red:expire(user_ip, expire_time)
    end
else
    if tonumber(res) == limit_request_times then
        -- ngx.say("request reach max limit times")
        ngx.exit(403)
        return
    else
        ok, err = red:incr(user_ip)
        if not ok then
            ngx.say("failed to increment request times")
            return
        else
            ngx.say("increment request times: ", res + 1)
        end
    end 
end
yunfeng.guo
  • 175
  • 1
  • 11

2 Answers2

9

Why not just use nginx build-in ngx_http_limit_req_module?

e.g. We limit not more than 2 requests per minute from one IP address。

http {
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/m;

...

server {

    ...

    location /search/ {
        limit_req zone=one burst=3 nodelay;
    }
xfeep
  • 1,091
  • 11
  • 12
  • Thx @xfeep, that's what i need. But it still can't fully meet my requirement. I need to limit request not only based on IP, and also based on request parameter, e.g /test?guid=blahblah, we need limit requests based on 'guid'. – yunfeng.guo Aug 01 '15 at 11:28
  • 1
    @yunfeng.guo please try limit_req_zone $arg_guid zone=one:10m rate=2r/m; and we can also try to combine IP and guid , e.g. limit_req_zone $binary_remote_addr$arg_guid zone=one:10m rate=2r/m; we can define serveral zones for different locations – xfeep Aug 02 '15 at 02:02
  • @yunfeng.guo Please note that "Prior to version 1.7.6, a key of limit_req_zone could contain exactly one variable." So if your nginx version is less than 1.7.6, you need define a variable and set it at location, e.g. set $myzonekey $binary_remote_addr$arg_guid; – xfeep Aug 02 '15 at 02:13
  • That's great, i will try it. Thanks a lot – yunfeng.guo Aug 02 '15 at 12:51
  • @xfeep can we block set request rate per hour ? – Mukesh Kumar Sep 07 '15 at 06:46
  • @MukeshKamboj AFAIK. per second and per minute are supported. per hour is not supported. – xfeep Sep 07 '15 at 07:40
  • @Xfeep thanks for the response. Do we have nginx configuration that set limit that an IP can send n request only for a day? I have such requirement that there is a service where i need to support only 20 to 30 requests in a day. – Mukesh Kumar Sep 07 '15 at 07:43
  • @MukeshKamboj No, so far ngx_http_limit_req_module has not supported it. – xfeep Sep 07 '15 at 10:18
  • 1
    @xfeep in case this is still relevant for you - [nginx-mod](https://www.getpagespeed.com/nginx-mod-a-better-faster-nginx-build) supports rate limiting per hour, day, week, month and year :) – Danila Vershinin Jul 10 '19 at 19:12
0

Also you can use resty.limit.conn and/or resty.limit.req modules via Lua https://nginx-extras.getpagespeed.com/lua/limit-traffic/

Hett
  • 3,484
  • 2
  • 34
  • 51