Nginx 按 IP 范围/子网限制请求,而不是单个 IP

Nginx 按 IP 范围/子网限制请求,而不是单个 IP

我可以使用 limit_conn_zone 指令来限制来自特定 IP 的传入连接速率。但是,如果我想将区域设置为不仅仅是 $remote_addr(这将为我提供世界上每个 IP 地址的单独限制),而是 $remote_addr 的 /16 子网,该怎么办?

答案1

limit_conn_zone 可以根据任何密钥应用限制,并且不要求密钥是 IP 地址;您不限于$remote_addr并且可以使用$remote_subnet

简而言之,你的问题就变成了:没有易于使用的预定义变量$remote_subnet可以用作ngx_http_limit_conn_module和/或ngx_http_limit_req_module

尝试定义一个子网作为密钥的问题在于,随着A/B/C 类网络寻址 并引入跨域路由包括 nginx 在内的应用程序并不知道特定远程 IP 地址属于哪个实际子网。对于 IPv4 地址和 IPv6 地址来说,都不知道。

此外,也没有 nginx 设置说明“总是假设子网掩码是/some_value计算应该属于的合成$remote_subnet值”$remote_addr采取一种愚蠢的做法。

这意味着您必须自己定义这样的函数并执行该计算。

据我所知,nginx 并不支持任何类型的计算,获取 IP 地址并正确计算给定子网掩码的网络 ID 可能需要使用 nginx lua 模块和一些自定义编码。

或者,对于足够大的子网,您可以考虑使用以下方法对查找表进行硬编码:地理模块

# Use the geo module lookup a synthetic $remote_subnet value
geo $remote_addr $remote_subnet {
    0.0.0.0/8     0.0.0.0;
    1.0.0.0/8     1.0.0.0;
    2.0.0.0/9     2.0.0.0;
    2.128.0.0/9   2.128.0.0;
    3.0.0.0/8     3.0.0.0;
    4.0.0.0/8     4.0.0.0;
    5.0.0.0/8     5.0.0.0;
    6.0.0.0/8     6.0.0.0;
    7.0.0.0/8     7.0.0.0;
    8.0.0.0/8     8.0.0.0;
    9.0.0.0/8     9.0.0.0;
    10.0.0.0/8   10.0.0.0;
    11.0.0.0/8   11.0.0.0;
    ...
}


# Requests with an empty $remote_subnet will not be accounted

limit_conn_zone $remote_subnet  zone=persubnet:10m;


server {
    ...
    limit_conn persubnet 10;
}

相关内容