Nginx limit_req 限制连接数用法示例

Anson 杂记 57 次浏览 评论已关闭

介绍一个 limit_req 经典配置方法,通过结合 map 使用,可以简化 Nginx 配置(实现在 server 块内添加 limit_req 限制,但仅作用于指定 URL。虽然也可以在 location 块里添加 limit_req 限制,但对于 php 资源的 location 块需要同时指定 fastcgi 配置,看起来略麻烦不够简洁)。

下面示例里的 map 之所以不用 $request_uri 是为防范含有重复 / 字符的不规范 URL 导致匹配失败逃逸限制,而 $uri 会去掉 URL 中的不规范字符。

limit_req 示例配置一

这个示例可以限制多个指定 URL,但每个 URL 都应用相同的限制速率。

限制效果:限制 WordPress 搜索/登录/注册/重置密码 URL 的请求数,每个 IP 每秒最多请求 5 次(均速处理,即每 200 毫秒处理 1 个请求),额外允许 10 个突发请求(即开始 200 毫秒实际允许处理 11 个请求,过后降至每 200 毫秒处理 2 个请求,因为突发名额每 200 毫秒释放 1 个),超出请求返回 429 错误。

http {
    ...
    map $uri$is_args$args $limit_req_level {
        default           "";
        ~\?(.*&)?s=       $binary_remote_addr;
        ~^/wp-login\.php  $binary_remote_addr;
    }
    limit_req_zone $limit_req_level zone=req_general:10m rate=5r/s;
    limit_req_status 429;
    ...
    server {
        ...
        limit_req zone=req_general burst=10 nodelay;
        ...
    }
}

limit_req 示例配置二

这个示例与上个的区别是可以对不同 URL 应用不同的限制速率,并且添加了全局限制(如不需要,删除其中创建 $req_general 变量的 map 块)。

限制效果:

  • 对所有 URL 限制请求数,每个 IP 每秒最多请求 20 次,允许 40 个突发请求
  • 对 WordPress XML-RPC URL 限制请求数,每个 IP 每秒最多请求 1 次,不允许并发请求
  • 对 WordPress 搜索/登录/注册/重置密码 URL 限制请求数,每个 IP 每秒最多请求 5 次,允许 10 个突发请求
http {
    ...
    map $uri$is_args$args $limit_req_level {
        default           0;
        ~^/xmlrpc\.php    1;
        ~\?(.*&)?s=       2;
        ~^/wp-login\.php  2;
    }
    map $limit_req_level $req_general {
        default  "";
        0        $binary_remote_addr;
    }
    map $limit_req_level $req_wpxmlrpc {
        default  "";
        1        $binary_remote_addr;
    }
    map $limit_req_level $req_wpsearch_wplogin {
        default  "";
        2        $binary_remote_addr;
    }
    limit_req_zone $req_general zone=req_general:10m rate=20r/s;
    limit_req_zone $req_wpxmlrpc zone=req_wpxmlrpc:10m rate=1r/s;
    limit_req_zone $req_wpsearch_wplogin zone=req_wpsearch_wplogin:10m rate=5r/s;
    limit_req_status 429;
    ...
    server {
        ...
        limit_req zone=req_general burst=40 nodelay;
        limit_req zone=req_wpxmlrpc nodelay;
        limit_req zone=req_wpsearch_wplogin burst=10 nodelay;
        ...
    }
}

limit_req 测试效果

安装 SIEGE WEB 压力测试工具(CentOS 安装命令,需已添加 EPEL 源)。

yum -y install siege

运行命令测试(其中 -r 指定测试次数,-c 指定并发请求数)。

siege -v --no-parser -b -r 1 -c 50 "https://example.com/wp-login.php"

注:当修改 limit_req 配置后,可能 nginx -s reload 不足以刷新配置,需要用 systemctl force-reload nginx 命令刷新。