我有一台NGINX服务器,该服务器为Web应用程序提供服务,客户可以在其中访问其网站的域(CNAMES)。
NGINX是否可以在一段时间内限制对其中一个域的访问数量?
例:
我需要的限制:2000个请求/域/分钟
因此,在一个特定的时间段内...
www.websiteA.com.br-1456个请求/分钟OK!
www.websiteB.com.br-1822个请求/分钟OK!
www.websiteC.com.br-2001年请求/分钟暂时锁定
有谁知道如何做这样的限制?
我正在使用nginx的速率限制功能来定义许多速率限制规则,然后将这些规则应用于特定主机。
这里有一些技巧(使用if语句以及通过error_page处理程序进行重定向)-我还没有找到更好的方法。如果您有更好的选择,请发表评论。
http {
# ...
# Define rate-limit key to use
map $http_authorization $rl_zone_key{
default $binary_remote_addr;
'~*.*' $http_authorization;
}
# Define Rate Limits
limit_req_zone $rl_zone_key zone=rateLimit_Standard:10m rate=1r/s;
limit_req_zone $rl_zone_key zone=rateLimit_Class_A:10m rate=5r/s;
limit_req_zone $rl_zone_key zone=rateLimit_Class_B:10m rate=10r/s;
limit_req_zone $rl_zone_key zone=rateLimit_Class_C:10m rate=100r/s;
# Define the rate Limit Category applied to the particular host
map $http_host $apply_rate_limit{
hostnames;
default rateLimit_Standard;
example.com rateLimit_Class_B;
*.example.com rateLimit_Class_A;
}
#upstream server definition for php fast-cgi using port 9000
upstream phpfcgi {
server 127.0.0.1:9000;
}
# ...
}
Run Code Online (Sandbox Code Playgroud)
$binary_remote_addr除非$http_authorization存在标头,否则用于比较两个请求是否来自同一位置的键使用nginx变量。这意味着,在对用户进行身份验证(使用摘要身份验证)之前,速率限制将通过ip应用-之后,它将由登录的用户会话应用。
在这里,我设置了速率限制缓存。
通过该map指令,我检入主机名$http_host以确定目标域,然后$apply_rate_limit使用要应用的速率限制类的名称进行定义。
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location / {
index index.php;
try_files $uri =404;
location ~ ^/index\.php(/|$) {
error_page 420 =200 @rateLimit_Standard;
error_page 421 =200 @rateLimit_Class_A;
error_page 422 =200 @rateLimit_Class_B;
error_page 423 =200 @rateLimit_Class_C;
if ( $apply_rate_limit = 'rateLimit_Standard' ) {return 420;}
if ( $apply_rate_limit = 'rateLimit_Class_A' ) {return 421;}
if ( $apply_rate_limit = 'rateLimit_Class_B' ) {return 422;}
if ( $apply_rate_limit = 'rateLimit_Class_C' ) {return 423;}
}
}
location @rateLimit_Standard {
limit_req zone=rateLimit_Standard burst=5;
add_header X-Rate-Limit-Class $apply_rate_limit;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass phpfcgi;
}
location @rateLimit_Class_A {
limit_req zone=rateLimit_Class_A burst=10 nodelay;
add_header X-Rate-Limit-Class $apply_rate_limit;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass phpfcgi;
}
location @rateLimit_Class_B {
limit_req zone=rateLimit_Class_B burst=100 nodelay;
add_header X-Rate-Limit-Class $apply_rate_limit;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass phpfcgi;
}
location @rateLimit_Class_C {
limit_req zone=rateLimit_Class_C burst=1000;
add_header X-Rate-Limit-Class $apply_rate_limit;
include external_definition_of_fastcgi_parameters.conf
}
}
Run Code Online (Sandbox Code Playgroud)
在示例虚拟主机文件中,我使用先前定义的速率限制类。可以用更直接的方式完成此操作,但在我们的方案中,我们有一个服务于多个域的单个vhost文件,因此,最好在vhost文件之外定义使用哪个速率限制类的域。
最后,我将提供一个简化的示例vhost文件,该文件删除了这种抽象并使vhost速率限制应用程序更加手动。
在nginx中,没有便捷的方法可以重定向到try_files指令之外的命名位置。要做到这一点,一个办法是定义一个错误处理程序(针对不常用的错误代码),然后提供命名位置作为error_page处理程序。
在这一行中,我们说的是,当错误代码420被触发时,错误处理程序应重定向到该@rateLimit_Standard
位置并将HTTP代码重置为200。
在我们的nginx.conf文件中,$apply_rate_limit是基于$http_host标题定义的。如果将其设置为rateLimit_Standard,则此if语句将通过从http请求返回,错误代码为420来完成。这将被我们之前定义的error_page处理程序捕获,并将被重定向到命名位置@rateLimit_Standard
将请求重新路由到后@rateLimit_Standard,它将应用速率限制并设置脉冲串值:limit_req zone=rateLimit_Standard burst=5;
然后它将按照正常方式继续处理php请求。
为了达到良好的效果,我还添加了一个标题来跟踪应用的速率限制:add_headerX-Rate-Limit-Class $apply_rate_limit;
您会注意到,对于每个命名位置,所包含的fcgi标头都是相同的。nginx配置块中没有正式的继承,因此必须对每个位置重复此继承,以将其转发到php-fpm。
但是,可以在外部文件中定义通用属性,并使用上面的include语句从单个外部文件中获取所有这些重复的配置选项。我把它留在这里是因为这是您真正应该做的。
上面的example.conf文件完整显示了我在环境中使用主机<->速率限制类配对时的抽象方式。
如果仅对单个域使用单个虚拟主机条目,则可能会简单得多:
server {
listen 80;
server_name simple-example.com;
root /var/www/simple-example.com;
location / {
index index.php;
try_files $uri =404;
location ~ ^/index\.php(/|$) {
limit_req zone=rateLimit_Class_A burst=10 nodelay;
add_header X-Rate-Limit-Class rateLimit_Class_A;
include fastcgi_params;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
fastcgi_pass phpfcgi;
}
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:上面的所有代码都是基于我自己的nginx配置构建的,目的是创建示例。这可能开箱即用,您需要将这些代码片段放入您的环境中,以使其正常工作。
如果您觉得这很有用,请投票。
| 归档时间: |
|
| 查看次数: |
3668 次 |
| 最近记录: |