在使用地图和地理模块的nginx中定义速率限制时,我需要帮助。
我已经定义了4种情况。这些情况中的每一种都应设置不同的速率限制:
geo $limited_ip {
default 0;
1.1.1.1/24 1;
2.2.2.2/24 2;
3.3.3.3/24 3;
}
我使用map模块将客户端的ip值传递给变量:
map $limited_ip $limited_ip_key {
0 '';
1 $binary_remote_addr;
2 $binary_remote_addr;
3 $binary_remote_addr;
}
现在,我设置了4个限制区域。最后一个区域用于测试:
limit_req_zone $limited_ip_key zone=zone0:10m rate=100r/m;
limit_req_zone $limited_ip_key zone=zone1:10m rate=200r/m;
limit_req_zone $limited_ip_key zone=zone2:10m rate=500r/m;
limit_req_zone $limited_ip_key zone=zone3:10m rate=1r/m;
最后,我将限制应用于server {}块:
limit_req zone=zone0 burst=10 nodelay;
limit_req zone=zone1 burst=10 nodelay;
limit_req zone=zone2 burst=10 nodelay;
limit_req zone=zone3 burst=1 nodelay;
配置测试是否正常,我也重新加载了nginx。使用apache Bench工具(ab)锤击Nginx服务器,看来zone3对于任何源IP总是匹配的。为什么来自其他遮罩的IP由地理模块匹配区域3定义?
日志:
*2757 limiting requests, excess: 1.697 by zone "zone3", client: 3.3.3.3, server: my.domain.com, request: "HEAD / HTTP/1.0", host: "my.domain.com"
*29449 limiting requests, excess: 1.958 by zone "zone3", client: 2.2.2.2, server: my.domain.com, request: "HEAD / HTTP/2.0", host: "my.domain.com"
我发现的所有结果都大约定义了2个区域,我找不到包含更多区域的示例。也许不可能这样做吗?
谢谢
答案 0 :(得分:0)
I was searching for the same configuration today and could not find an example with more than 2 zones too. So here is what in theory should work (I have not yet tried it out) :
geo $limited_ip {
default 0;
1.1.1.1/24 1;
2.2.2.2/24 2;
3.3.3.3/24 3;
}
map $limited_ip $limited_ip_key0 {
0 $binary_remote_addr;
1 '';
2 '';
3 '';
}
map $limited_ip $limited_ip_key1 {
0 '';
1 $binary_remote_addr;
2 '';
3 '';
}
map $limited_ip $limited_ip_key2 {
0 '';
1 '';
2 $binary_remote_addr;
3 '';
}
map $limited_ip $limited_ip_key3 {
0 '';
1 '';
2 '';
3 $binary_remote_addr;
}
limit_req_zone $limited_ip_key0 zone=zone0:10m rate=100r/m;
limit_req_zone $limited_ip_key1 zone=zone1:10m rate=200r/m;
limit_req_zone $limited_ip_key2 zone=zone2:10m rate=500r/m;
limit_req_zone $limited_ip_key3 zone=zone3:10m rate=1r/m;
limit_req zone=zone0 burst=10 nodelay;
limit_req zone=zone1 burst=10 nodelay;
limit_req zone=zone2 burst=10 nodelay;
limit_req zone=zone3 burst=1 nodelay;
Explanation:
a) if IP is none of the 3 defined then
$limited_ip_key0 = $binary_remote_addr
$limited_ip_key1 = ''
$limited_ip_key2 = ''
$limited_ip_key3 = ''
thus the zone0 will be matched only, and the rate limit of 100r/m will be applied
b) if IP is 1.1.1.1/24
$limited_ip_key0 = ''
$limited_ip_key1 = $binary_remote_addr
$limited_ip_key2 = ''
$limited_ip_key3 = ''
thus the zone1 will be matched only, and the rate limit of 200r/m will be applied
c) if IP is 2.2.2.2/24
$limited_ip_key0 = ''
$limited_ip_key1 = ''
$limited_ip_key2 = $binary_remote_addr
$limited_ip_key3 = ''
thus the zone2 will be matched only, and the rate limit of 500r/m will be applied
d) if IP is 3.3.3.3/24
$limited_ip_key0 = ''
$limited_ip_key1 = ''
$limited_ip_key2 = ''
$limited_ip_key3 = $binary_remote_addr
thus the zone3 will be matched only, and the rate limit of 1r/m will be applied
Here is a php script to automatically create the required zones so you can be able to administer more zones and ips easily
<?php
list($mapString, $zonesString, $zonesArray) = createZones(
"myendpoint",
array(
"default"=>array(
"zoneSize"=>"10m",
"rate"=>"10r/s",
"burst"=>"100",
"options"=>""
),
"zone1"=>array(
"ips"=>array(
"11.11.11.11/32",
"1.1.1.1/24"
),
"zoneSize"=>"10m",
"rate"=>"10r/s",
"burst"=>"100",
"options"=>""
),
"zone2"=>array(
"ips"=>array(
"22.22.22.22/32",
"2.2.2.2/24"
),
"zoneSize"=>"10m",
"rate"=>"20r/s",
"burst"=>"100",
"options"=>"nodelay"
),
"zone3"=>array(
"ips"=>array(
"33.33.33.33/32",
"3.3.3.3/24"
),
"zoneSize"=>"10m",
"rate"=>"30r/s",
"burst"=>"100",
"options"=>""
),
)
);
echo "# Define the ips and maps\n$mapString\n#Define the zones\n$zonesString\n\n";
echo "\t# limit directives to be placed inside the location section\n";
foreach ($zonesArray as $zoneName=>$zoneString) {
echo "\t$zoneString\n";
}
function createZones($endpointPrefix,$zones) {
$mapString0='geo $'.$endpointPrefix.' {'."\n\t\tdefault\t0;";
$mapString1='';
$zonesString='';
$zonesArray=array();
$zoneNum=0;
foreach ($zones as $zoneName=>$params) {
$zoneName=strtolower($zoneName);
if ($zoneName!='default') {
$zoneNum++;
foreach($params['ips'] as $ip) {
$mapString0.="\n\t\t$ip\t$zoneNum;";
}
}
}
$mapString0.="\n}\n";
$zoneNumTotal=$zoneNum;
// now that we now the total zones we can create the maps
$zoneNum=0;
foreach ($zones as $zoneName=>$params) {
$zoneName=strtolower($zoneName);
$mapString1.='map $'.$endpointPrefix.' $'.$endpointPrefix.'_key_'.$zoneName.' {';
for($zoneNumTemp=0;$zoneNumTemp<=$zoneNumTotal;$zoneNumTemp++) {
if ($zoneNum==$zoneNumTemp) {
$mapString1.="\n\t\t$zoneNumTemp\t\$binary_remote_addr;";
} else {
$mapString1.="\n\t\t$zoneNumTemp\t'';";
}
}
$mapString1.="\n}\n\n";
$zoneNum++;
}
// now create the actual zones string
foreach ($zones as $zoneName=>$params) {
$zoneName=strtolower($zoneName);
$zonesString.="\n";
if ( isset( $params['ips']) ) {
foreach ($params['ips'] as $ip) {
$zonesString .= "# $ip\n";
}
}
$zonesString.='limit_req_zone $'.$endpointPrefix.'_key_'.$zoneName.' zone='.$endpointPrefix.'_'.$zoneName.':'.$params['zoneSize'].' rate='.$params['rate'].';';
$zonesString.="\n";
}
// now create the limits that should be applied inside the location sections
foreach ($zones as $zoneName=>$params) {
$zoneName=strtolower($zoneName);
$zonesArray[$zoneName]='limit_req zone='.$endpointPrefix.'_'.$zoneName;
if ($params['burst']) {
$zonesArray[$zoneName].=' burst='.$params['burst'];
}
if ($params['options']) {
$zonesArray[$zoneName].=' '.$params['options'];
}
}
return array($mapString0."\n".$mapString1, $zonesString,$zonesArray);
}
When executed the above script produces:
# Define the ips and maps
geo $myendpoint {
default 0;
11.11.11.11/32 1;
1.1.1.1/24 1;
22.22.22.22/32 2;
2.2.2.2/24 2;
33.33.33.33/32 3;
3.3.3.3/24 3;
}
map $myendpoint $myendpoint_key_default {
0 $binary_remote_addr;
1 '';
2 '';
3 '';
}
map $myendpoint $myendpoint_key_zone1 {
0 '';
1 $binary_remote_addr;
2 '';
3 '';
}
map $myendpoint $myendpoint_key_zone2 {
0 '';
1 '';
2 $binary_remote_addr;
3 '';
}
map $myendpoint $myendpoint_key_zone3 {
0 '';
1 '';
2 '';
3 $binary_remote_addr;
}
#Define the zones
limit_req_zone $myendpoint_key_default zone=myendpoint_default:10m rate=10r/s;
# 11.11.11.11/32
# 1.1.1.1/24
limit_req_zone $myendpoint_key_zone1 zone=myendpoint_zone1:10m rate=10r/s;
# 22.22.22.22/32
# 2.2.2.2/24
limit_req_zone $myendpoint_key_zone2 zone=myendpoint_zone2:10m rate=20r/s;
# 33.33.33.33/32
# 3.3.3.3/24
limit_req_zone $myendpoint_key_zone3 zone=myendpoint_zone3:10m rate=30r/s;
# limit directives to be placed inside the location section
limit_req zone=myendpoint_default burst=100
limit_req zone=myendpoint_zone1 burst=100
limit_req zone=myendpoint_zone2 burst=100 nodelay
limit_req zone=myendpoint_zone3 burst=100