Jak ograniczyć stawki w Nginx, ale włączając / wyłączając niektóre adresy IP?
27
Jestem w stanie limit_reqograniczyć liczbę żądań do mojego serwera.
Chciałbym jednak usunąć ograniczenie szybkości dla niektórych adresów IP (tj. Białej listy) i zastosować inne ograniczenie prędkości dla niektórych innych (tj. Niektórych adresów IP, które chciałbym mieć tylko 1r / s).
Próbowałem użyć warunków warunkowych (np. if ( $remote_addr = "1.2.3.4" ) {}), Ale wydaje się, że działa to tylko z regułami przepisywania, a nie z regułami ograniczenia prędkości.
Naprawdę lepiej jest unikać stosowania dyrektywy „jeśli”. Kiedy klucz w limit_req_zone (i limit_conn_zone) jest pusty, limity nie są stosowane. Możesz użyć tego w połączeniu z mapą i modułami geograficznymi, aby utworzyć białą listę adresów IP, w których ograniczenia przepustnicy nie są stosowane.
Ten przykład pokazuje, jak skonfigurować limit zarówno dla równoczesnych żądań, jak i częstotliwości żądań z jednego adresu 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;
Dyrektywy stref muszą być umieszczone na poziomie http, jednak pozostałe dyrektywy mogą być umieszczone niżej, np. Na poziomie serwera lub lokalizacji, aby ograniczyć ich zakres lub jeszcze bardziej dostosować limity.
Zgodnie z komentarzami, pierwsze ogranicza równoczesne połączenia, drugie ogranicza szybkość połączeń
shonky użytkownik systemu Linux
Czy możesz wyjaśnić, dlaczego wykonujesz mapowanie w dwóch etapach, a geonastępnie mapzamiast geoustawiać $limitbezpośrednio?
Marcus Downing
2
Wygląda na to, że geonie można odwzorować na zmienną, więc jeśli podasz $binary_remote_addrjako wartość odwzorowania, przełoży się to na ciąg literalny "$binary_remote_addr", a nie na wartość zmiennej.
ColinM
1
Chciałbym dodać, że jeśli dany adres IP znajduje się już w strefie, musisz zrestartować nginx; przeładowanie to za mało.
Halfgaar
5
Możesz bezpiecznie używać nazwanych lokalizacji, takich jak „@lokalizacja” w bloku if ().
Nie jestem pewien, czy rozumiem część 410? Czy klient faktycznie widzi kod statusu HTTP 410?
svrist
1
Wow, to naprawdę działa! Bardzo fajna error_pagesztuczka, +1! @svrist, zobacz serverfault.com/a/870170/110020, aby uzyskać pełne wyjaśnienie, jak coś takiego mogłoby działać i dlaczego.
geo
następniemap
zamiastgeo
ustawiać$limit
bezpośrednio?geo
nie można odwzorować na zmienną, więc jeśli podasz$binary_remote_addr
jako wartość odwzorowania, przełoży się to na ciąg literalny"$binary_remote_addr"
, a nie na wartość zmiennej.Możesz bezpiecznie używać nazwanych lokalizacji, takich jak „@lokalizacja” w bloku if ().
Zobacz: http://wiki.nginx.org/IfIsEvil
Coś takiego powinno działać:
Wpisz „location @slowdown {}” tymi samymi informacjami, co „location / {}, takie jak proxy_pass, jeśli używasz nginx jako odwrotnego proxy.
źródło
error_page
sztuczka, +1! @svrist, zobacz serverfault.com/a/870170/110020, aby uzyskać pełne wyjaśnienie, jak coś takiego mogłoby działać i dlaczego.