Comment limiter les taux dans nginx, mais en incluant / excluant certaines adresses IP?
27
Je peux utiliser limit_reqpour limiter la fréquence de toutes les demandes à mon serveur.
Cependant, je voudrais supprimer la restriction de débit pour certaines adresses IP (c'est-à-dire la liste blanche) et utiliser une restriction de débit différente pour certaines autres (c'est-à-dire certaines IP que j'aimerais aussi bas que 1r / s).
J'ai essayé d'utiliser des conditions (par exemple if ( $remote_addr = "1.2.3.4" ) {}), mais cela semble fonctionner uniquement avec des règles de réécriture, pas pour des règles de limite de débit.
Il est vraiment préférable d'éviter d'utiliser la directive "if". Lorsque la clé de limit_req_zone (et limit_conn_zone) est vide, les limites ne sont pas appliquées. Vous pouvez l'utiliser en conjonction avec les modules de carte et de géo pour créer une liste blanche d'adresses IP où les limites de limitation ne sont pas appliquées.
Cet exemple montre comment configurer une limite pour les demandes simultanées et le taux de demande à partir d'une seule 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;
Les directives de zone doivent être placées au niveau http, mais les autres directives peuvent être placées plus bas, par exemple au niveau du serveur ou de l'emplacement pour limiter leur portée ou adapter davantage les limites.
Selon les commentaires, le premier limite les connexions simultanées, le second limite le taux de connexions
shonky linux user
Pouvez-vous expliquer pourquoi vous effectuez le mappage en deux étapes, geosuivi de map, plutôt que de simplement utiliser geopour définir $limitdirectement?
Marcus Downing du
2
Il semble geoimpossible de mapper sur une variable, donc si vous spécifiez $binary_remote_addrune valeur de mappage, cela se traduira par la chaîne littérale "$binary_remote_addr", et non par la valeur de la variable.
ColinM
1
Je voudrais ajouter que si l'IP en question est déjà dans la zone, vous devez redémarrer nginx; un rechargement ne suffit pas.
Halfgaar
5
Vous pouvez utiliser en toute sécurité des emplacements nommés, tels que "@location" dans un bloc if ().
Je ne suis pas sûr de comprendre la partie 410? Le client voit-il réellement un code d'état http 410?
svrist
1
Wow, cela fonctionne réellement! Astuce très astucieuse error_page, +1! @svrist, voir serverfault.com/a/870170/110020 pour une explication complète du fonctionnement de quelque chose comme ça, et pourquoi.
geo
suivi demap
, plutôt que de simplement utilisergeo
pour définir$limit
directement?geo
impossible de mapper sur une variable, donc si vous spécifiez$binary_remote_addr
une valeur de mappage, cela se traduira par la chaîne littérale"$binary_remote_addr"
, et non par la valeur de la variable.Vous pouvez utiliser en toute sécurité des emplacements nommés, tels que "@location" dans un bloc if ().
Voir: http://wiki.nginx.org/IfIsEvil
Quelque chose comme ça devrait fonctionner:
Remplissez "location @slowdown {}" avec les mêmes informations que "location / {}, comme proxy_pass si vous utilisez nginx comme proxy inverse.
la source
error_page
, +1! @svrist, voir serverfault.com/a/870170/110020 pour une explication complète du fonctionnement de quelque chose comme ça, et pourquoi.