¿Cómo limitar la velocidad en nginx, pero incluyendo / excluyendo ciertas direcciones IP?
27
Puedo usar limit_reqpara limitar todas las solicitudes a mi servidor.
Sin embargo, me gustaría eliminar la restricción de velocidad para ciertas direcciones IP (es decir, la lista blanca) y usar una restricción de velocidad diferente para ciertas otras (es decir, ciertas direcciones IP que me gustaría tan bajas como 1r / s).
Intenté usar condicionales (por ejemplo if ( $remote_addr = "1.2.3.4" ) {}), pero parece funcionar solo con reglas de reescritura, no para reglas de límite de velocidad.
Es realmente mejor evitar usar la directiva "if". Cuando la clave en limit_req_zone (y limit_conn_zone) está vacía, los límites no se aplican. Puede usar esto junto con los módulos de mapa y geo para crear una lista blanca de IP donde no se aplican los límites de aceleración.
Este ejemplo muestra cómo configurar un límite para las solicitudes concurrentes y la velocidad de solicitud desde una sola IP.
http {
geo $whitelist {
default 0;
# CIDR in the list below are not limited
1.2.3.0/24 1;
9.10.11.12/32 1;
127.0.0.1/32 1;
}
map $whitelist $limit {
0 $binary_remote_addr;
1 "";
}
# The directives below limit concurrent connections from a
# non-whitelisted IP address to five
limit_conn_zone $limit zone=connlimit:10m;
limit_conn connlimit 5;
limit_conn_log_level warn; # logging level when threshold exceeded
limit_conn_status 503; # the error code to return
# The code below limits the number requests from a non-whitelisted IP
# to one every two seconds with up to 3 requests per IP delayed
# until the average time between responses reaches the threshold.
# Further requests over and above this limit will result
# in an immediate 503 error.
limit_req_zone $limit zone=one:10m rate=30r/m;
limit_req zone=one burst=3;
limit_req_log_level warn;
limit_req_status 503;
Las directivas de zona deben colocarse en el nivel http, sin embargo, las otras directivas pueden ubicarse más abajo, por ejemplo, en el servidor o en el nivel de ubicación para limitar su alcance o adaptar aún más los límites.
Según los comentarios, el primero limita las conexiones concurrentes, el segundo limita la velocidad de las conexiones
usuario de shonky linux el
¿Puede explicar por qué hace el mapeo en dos etapas, geoseguidas por map, en lugar de solo usar geopara establecer $limitdirectamente?
Marcus Downing
2
Parece geoque no se puede asignar a una variable, por lo que si especifica $binary_remote_addrcomo valor de asignación, esto se traducirá en la cadena literal "$binary_remote_addr", no en el valor de la variable.
ColinM
1
Me gustaría agregar que si la IP en cuestión ya está en la zona, debe reiniciar nginx; una recarga no es suficiente.
Halfgaar
5
Puede usar ubicaciones con nombre de forma segura, como "@location" en un bloque if ().
¿No estoy seguro de entender la parte 410? ¿El cliente realmente ve un código de estado http 410?
svrist
1
Wow, esto realmente funciona! error_pageTruco muy ingenioso , +1! @svrist, consulte serverfault.com/a/870170/110020 para obtener una explicación completa de cómo funcionaría algo así y por qué.
geo
seguidas pormap
, en lugar de solo usargeo
para establecer$limit
directamente?geo
que no se puede asignar a una variable, por lo que si especifica$binary_remote_addr
como valor de asignación, esto se traducirá en la cadena literal"$binary_remote_addr"
, no en el valor de la variable.Puede usar ubicaciones con nombre de forma segura, como "@location" en un bloque if ().
Ver: http://wiki.nginx.org/IfIsEvil
Algo como esto debería funcionar:
Complete "location @slowdown {}" con la misma información que "location / {}, como proxy_pass si está usando nginx como proxy inverso.
fuente
error_page
Truco muy ingenioso , +1! @svrist, consulte serverfault.com/a/870170/110020 para obtener una explicación completa de cómo funcionaría algo así y por qué.