通过nginx配置拦截某些IP访问的方式,限制IP每秒的请求次数

有时候需要在nginx配置一些禁止访问的IP,或者只配置一些可以访问的IP,下面的一些nginx里面配置的方法。

①直接写deny,去禁止某些IP地址,在指定的IP里面访问者会收到403返回。

server {
      

    location / {
        # 拒绝一个IP范围
        deny 192.168.1.0/24;

        # 拒绝特定的IP地址
        deny 192.168.2.1;
        deny 192.168.2.2;

        # 允许其他所有IP地址
        allow all;
    }
}

image.png

②如果要开放某些IP访问,其他的禁用,刚好相反设置:

location / {
    allow 192.168.1.0/24;# 允许特定的IP地址范围
    deny all;# 禁止其他所有IP地址
}


③动态黑名单

根据某些条件动态拦截IP,可以结合使用Nginx和外部脚本。

  • 创建一个黑名单文件,例如/var/nginx/blacklist.txt

  • 在Nginx配置中使用http_access_module来引用这个文件。

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format  main  '$remote_addr -$remote_user [$time_local] "$request" '
                      '$status$body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    # Include the blacklist
    include /etc/nginx/blacklist.conf;
}

/etc/nginx/blacklist.conf文件中:

geo $block {
    default 0;
    include /var/nginx/blacklist.txt;#加载名单
}

map $block$limit {
    1 "";
    0 $binary_remote_addr;
}

limit_req_zone $limit zone=one:10m rate=1r/s;
  • map 指令用于根据变量$block的值设置另一个变量$limit的值。

  • 1 ""; 表示如果$block的值是1(即在黑名单中),则$limit被设置为空字符串(这将阻止请求)。

  • 0 $binary_remote_addr; 表示如果$block的值是0(即不在黑名单中),则$limit被设置为客户端的IP地址的二进制表示(这允许请求通过)。

  • limit_req_zone 指令定义了一个共享内存区域zone,用于存储IP地址的请求频率信息。

  • $limit 是根据前面map指令设置的变量。

  • zone=one:10m 定义了区域名称one和分配给它的内存大小(10MB)。

  • rate=1r/s 设置了每个IP地址每秒允许的最大请求数量。在这个例子中,每个IP地址每秒最多只能有一个请求



然后在的location块中使用limit_req指令:

location / {
    limit_req zone=one burst=5;
    # 其他配置...
}


然后需要一个脚本来更新blacklist.txt文件,这可以通过分析访问日志、监控系统活动等方式实现。

/var/nginx/blacklist.txt 文件是Nginx geo 指令用来定义IP地址黑名单的文件。该文件的格式相对简单,每行包含一个IP地址或一个IP地址范围,后面跟着一个空格和一个值,通常这个值是1,表示该IP地址或范围应该被阻止。以下是该文件可能包含的内容的示例

192.168.1.1 1
192.168.1.2 1
192.168.1.3 1
192.168.1.0/24 1


④高级点的哈,有点小开销哦——使用Lua脚本和Redis模块

1. 使用Lua脚本和Redis模块

Nginx可以通过Lua模块(ngx_lua)来执行Lua脚本,并且可以使用Lua库如resty.redis与Redis进行交互。以下是一个基本的示例,展示如何在Nginx中使用Lua来检查Redis中的黑名单:

首先,确保你的Nginx安装了ngx_lua模块和resty.redis库。

http {
    # 设置Lua包路径
    lua_package_path '/path/to/lua-resty-redis/lib/?.lua;;';

    server {
        listen       80;
        server_name  localhost;

        location / {
            access_by_lua_block {
                local redis = require "resty.redis"
                local red = redis:new()
                red:set_timeout(1000) -- 1 second

                local ok, err = red:connect("127.0.0.1", 6379)
                if not ok then
                    ngx.log(ngx.ERR, "failed to connect to redis: ", err)
                    return ngx.exit(500)
                end

                local ip = ngx.var.binary_remote_addr
                local is_blocked = red:sismember("ip_blacklist", ip)

                if is_blocked then
                    ngx.log(ngx.ERR, "IP ", ip, " is blocked")
                    return ngx.exit(403)
                end
            }

            # 其他location配置...
        }
    }
}


在这个配置中:

  • access_by_lua_block 是在请求被处理之前执行的Lua代码块。

  • 使用resty.redis库连接到Redis服务器,并检查当前请求的IP是否在名为ip_blacklist的Redis集合中。

使用Lua脚本和Redis模块会引入额外的性能开销。



补充,有时候会限制IP每秒的请求次数:

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

    server {
        location / {
            limit_req zone=mylimit burst=5 nodelay;
            ...
        }
    }
}

它限制了每个客户端IP每秒钟只能发起10个请求。在这个配置中,$binary_remote_addr变量用于获取客户端IP地址,zone=mylimit:10m定义了一个名为mylimit的共享内存区域,大小为10MB,用于存储每个IP的请求状态。rate=10r/s设置了每秒允许的最大请求数。burst=5表示允许短时间内超过限制的请求数量,nodelay表示不对超出限制的请求进行延迟处理。


评论/留言