我可以使用 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;
}