Estoy intentando proteger Drupal que se ejecuta en Nginx de DDoS simples con limit_conn y limit_req. Pero encontré un comportamiento extraño con la herencia de limit_conn
directiva que no puedo explicar.
He reducido mi configuración de nginx (1.8.0) a este mínimo, lo que muestra el problema:
limit_conn_zone $binary_remote_addr zone=perip:10m;
server {
server_name test.dev;
root /var/nginx/drupal; ## <-- Your only path reference.
#Allow not more than 10 simultaneous connections from one address.
limit_conn perip 10;
location / {
#limit_conn perip 1;
# This is cool because no php is touched for static content
try_files $uri @rewrite;
}
location @rewrite {
# Clean URLs are handled in drupal_environment_initialize().
rewrite ^ /index.php;
}
location ~ \.php$ {
#Allow not more than 1 simultaneous *connection_to_PHP* from one address.
limit_conn perip 1;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
}
Como puede ver, quiero limitar el número de conexiones simultáneas a 10 para todas las solicitudes y a 4 para el backend de php.(En este ejemplo he modificado la conexión 4 a 1, por lo que sería más fácil de activar)
La documentación de Nginx enhttp://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_connEstablece que:
Estas directivas se heredan del nivel anterior si y sólo si no hay
limit_conn
directivas en el nivel actual.
Pero sucede algo extraño en mis pruebas, parece que nginx está ignorando la directiva limit_conn
dentro del location ~ \.php$
bloque:
- Cuando pruebo esta configuración con 5 conexiones simultáneas
ab -n 100 -c 5 http://test.dev/
, no se produce ningún bloqueo. Tan pronto como elevo el
límite a 11,-c 11
nginx comienza a bloquear solicitudes. - Si modifico el límite de conexiones globales de 10 a 5, nginx limita más de 6 conexiones (
-c 6
); parece quelocation ~ \.php$
se ignora la directiva en el bloque. - Si elimino la
conn_limit
directiva a nivel de servidor, la directiva enlocation ~ \.php$
bloque, ¡de repente comienza a funcionar! - Aún más confuso: si agrego la
conn_limit
directivalocation /
bloquear, ¡sobrescribe correctamente la global!
¿Quizás el problema esté en try_files
la directiva o en múltiples redirecciones? Estaría muy agradecido si alguien pudiera explicar por qué la conn_limit
directiva no se sobrescribe, como se esperaba.
Respuesta1
Gracias a @AlexeyTen, espero poder responder la pregunta.
Importantes son dos puntos:
- ¡La
limit_conn
directiva se procesa solo una vez por solicitud! - Estas directivas se heredan del nivel anterior si y sólo si no hay
limit_conn
directivas en el nivel actual.
TL;DR: si hay una limit_conn
directiva, nginx mira el bloque secundario en la cadena de ejecución, si no la hay limit_conn
, se procesa el principal. Después de eso limit_conn
, se ignoran todas las demás directivas.
Intento explicarlo con mi ejemplo:
En el ejemplo que publiqué, cuando un "http://test.dev/"La solicitud llega, al principio, nginx no está procesando limit_conn
a server
nivel, pero espera para buscar la ubicación coincidente location /
. Pero en este nivel no hay ninguna limit_conn
directiva, por lo que nginx procesa la que está en el server
nivel. Después de eso, todas limit_conn
las directivas se ignoran, porque ya fue procesado. Eso explica mis pruebas 1-3.
En la prueba 4, nginx encuentra una limit_conn
directiva en la ubicación location /
y la procesa, pero nuevamente, en la ubicación location @rewrite
no se encuentra, por lo que se procesa limit_conn
la directiva en . location /
Nuevamente estamos ignorando el location ~ \.php$
bloqueo.