The limit_conn_zone
can apply limits based on any key and doesn't require that the key is an IP-address; you're not limited to $remote_addr
and you can use $remote_subnet
.
In short your problem then becomes: there is no easily used pre-defined variable $remote_subnet
that can be used as key for the ngx_http_limit_conn_module and/or ngx_http_limit_req_module.
The problem with trying to define a subnet to use as a key is that with the abolishment of A/B/C classful network addressing and the introduction of CIDR applications including nginx have no idea what actual subnet a particular remote IP-address belongs to. Not for IPv4 addresses and certainly not for IPv6 addresses.
Also there is also no nginx setting that says "always assume the subnet mask to be /some_value
to calculate a synthetic $remote_subnet
value which $remote_addr
should belong to" for a dumb approach.
That means you have to define such a function and perform that calculation yourself.
As far as I know nginx doesn't have such native support for calculations of any kind and taking an IP address and properly calculating for a given subnet mask the network ID will probably require using the nginx lua module and a bit of custom coding.
Alternatively for large enough subnets you could consider hardcoding a lookup table with for example the geo module.
# 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;
}