NGINX-hastighet Limiting stoppar automatiserade förfrågningar, dämpar toppbelastningar och skyddar inloggnings-, API- och formulärändpunkter mot botar och attacker. Jag visar dig hur du definierar gränsvärden och använder dem för Skydd mot botar använder och utifrån detta utformar ett robust säkerhetskoncept för välbesökta webbplatser.
Centrala punkter
Väsentligt Dessa är de viktigaste budskapen:
- Gränsvärden för priser förhindrar skadliga attacker och skyddar backend-resurserna.
- Burst/utan fördröjning fångar upp legitima toppar utan att blockera användare.
- Zoner skilja mellan människor och botar med olika gränser.
- Loggning tillhandahåller data för att iterativt skärpa gränserna.
- Integration med WAF, DDoS-skydd och övervakning ökar effektiviteten.
Varför rate limiting stoppar attacker i ett tidigt skede
Angriparna satsar på höga Begäranfrekvenser, för att missbruka inloggningsformulär, överbelasta API:er eller automatiskt skrapa innehåll. Därför begränsar jag antalet förfrågningar per nyckel – oftast per IP-adress – och avgör om jag ska begränsa dem, fördröja dem eller svara med 429. På så sätt håller jag bort bottrafik från CPU, databasen och applikationslogiken och släpper igenom legitima användare. Särskilt känsliga sökvägar som /login, /auth, /xmlrpc.php eller resurskrävande sökningar gynnas av detta. Källan till denna metod är Nginx-dokumentation om ngx_http_limit_req_module.
Hur NGINX-modulen fungerar i praktiken
Modulen fungerar enligt principen Läckande skopa-Princip: För varje nyckel lagrar NGINX räknarvärden i en zon och jämför dem med den tillåtna hastigheten. Typiska nycklar är $binary_remote_addr för IP-adresser, token för API-nycklar eller härledda värden via map. Om en klient kontinuerligt överskrider hastigheten och burst-bufferten avvisar NGINX begäran innan den når backend. Detta sparar beräkningstid och minskar fördröjningarna för riktiga besökare. Jag ställer in reaktionen på 429 Too Many Requests eller valfritt en annan Statuskod um.
Konfiguration: Förklarat steg för steg
Jag börjar med en zon i http-sektionen, ställer in en måttlig hastighet och aktiverar den selektivt på känsliga vägar. För kortvariga toppar definierar jag en burst, eventuellt med nodelay, för att undvika plötsliga avvisningar. Därefter testar jag i stagingmiljön och utvärderar loggarna innan jag aktiverar den i produktionsmiljön. På så sätt riskerar jag inte onödiga spärrar för riktiga användare. Ett kortfattat exempel illustrerar detta Syntax påtaglig:
# http {}
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
server {
location /api/ {
limit_req zone=req_limit_per_ip burst=20 nodelay;
limit_req_status 429;
}
location /login {
limit_req zone=req_limit_per_ip burst=5;
limit_req_status 429;
}
}
Botskydd med zoner och User-Agent-logik
IP-baserade begränsningar räcker sällan mot distribuerade botnät, därför delar jag upp trafiken i Zoner: Människor tilldelas generösare värden, medan generiska sökrobotar får strängare. Med map utvärderar jag användaragenter, identifierar godkända botar som Googlebot och tilldelar dem egna, noggrant övervakade gränser. För okända skrapare sätter jag hårda gränser på kostsamma sökvägar. Om mönster upptäcks skärper jag kraven dynamiskt tills Pris återigen ligger inom det normala intervallet.
Finjustering: hastighet, burst, nodelay och statuskoder
Rate styr genomströmningen per sekund, Burst tillåter kortvariga buffringar och nodelay avgör om jag föredrar buffring eller omedelbar vidarebefordran. Jag börjar försiktigt, t.ex. 10 r/s med burst 20 på API:er, och finjusterar sedan utifrån logganalysen. För inloggningsrutter ställer jag t.ex. in 1 r/s med liten burst för att bromsa brute-force-attacker. Vid överskridanden returnerar jag 429, eftersom klienter då klara av och att Retry-logiken fungerar som den ska. I särskilda fall använder jag alternativa koder om klienterna begär det.
Översikt i tabellen: Riktlinjer och tillämpning
Följande Tabell sammanfattar centrala riktlinjer och visar när de är lämpliga.
| direktiv | Effekt | Exempel | Typisk användning |
|---|---|---|---|
| limit_req_zone | Ange nyckel, zon och Pris fast | limit_req_zone $binary_remote_addr zone=perip:10m rate=10r/s; | Grundbelopp per IP-adress, token eller användaragent |
| limit_req | Aktiverar gränsen i Plats/Server | limit_req zone=perip burst=20 nodelay; | Finjustering per sökväg eller vHost |
| limit_req_status | Lägger till HTTP-kod Överskridande | limit_req_status 429; | Korrekt klientbeteende och nya försök |
| karta | Vidarebefordrar förfrågningar till Zoner på | map $http_user_agent $is_bot {…} | Åtskillnad mellan bot och människa utifrån User-Agent |
I praktiken: Skydda inloggningspunkten på ett målinriktat sätt
Jag begränsar /login mycket strikt, eftersom botar provar lösenord med hög Frekvens Testa dig fram. 1 förfrågan per sekund med burst 3 förhindrar massiv gissning utan att drabba riktiga användare för hårt. Dessutom loggar jag upprepade misslyckade inloggningsförsök för att tillfälligt spärra IP-adresser. I kombination med tvåfaktorsautentisering (2FA) och valfritt Captcha minskar belastningen på databasen och sessionshanteringen märkbart. På så sätt håller jag antalet misslyckade inloggningsförsök på en låg nivå och säkerställer att Tillgång redo och stabil.
I praktiken: Tillhandahålla API:er på ett rättvist och kontrollerat sätt
API:er kräver tydliga Odds, så att enskilda klienter inte tar upp hela bandbredden. För allmänna rutter ställer jag in 10r/s och burst 20, för kostsamma slutpunkter strängare värden. Om tokens eller API-nycklar finns tillgängliga begränsar jag per token istället för per IP-adress. Detta skapar rättvisa mellan kunderna och förhindrar missbruk. En mer ingående beskrivning finns i min anmärkning om API-begränsning av antalet förfrågningar, som ger en bredare inramning av begreppet.
Övervakning, loggning och iterativ finjustering
Jag loggar 429-svar inklusive Nyckel (t.ex. IP-adress eller token) och sökväg för att upptäcka mönster. Plötsliga toppar på ett fåtal sökvägar tyder på webbskrapning eller brute-force-attacker; en jämnt fördelad belastning tyder på botnät. Med hjälp av dessa data sätter jag gränser endast där det är nödvändigt och minimerar antalet falska positiva resultat. Dashboards med frekvens, felprocent och latens visar mig effekten av varje ändring. På så sätt förblir Prestanda hög, samtidigt som skyddet ökar.
Integrering i ett helhetsinriktat skyddskoncept
Jag anser att Rate Limiting är ett starkt första steg skikt, men jag kombinerar det med WAF-regler, IP-reputation och TLS-härdning. Mot volymattacker hjälper ett uppströms DDoS-skydd som filtrerar trafiken på nätverksnivå innan NGINX behöver träda in. Jag mäter kontinuerligt nyckeltal, ställer in larm vid ovanliga toppar och reagerar med regeluppdateringar. På så sätt skapas ett robust skyddsnätverk av flera byggstenar. Dessa ger en praktisk översikt DDoS-strategier.
Konkreta konfigurationsmönster för botar jämfört med människor
Jag delar upp besökarna i kategorier med hjälp av map och hänvisar dem till egna Zoner. Kända sökrobotar tilldelas måttliga gränser, medan generiska agenter får strängare gränser. För sökvägar som /search eller /report är jag strängare, eftersom de tar upp mycket CPU-kapacitet. Vid återkommande överträdelser höjer jag inte gränserna, utan spärrar tillfälligt eller flyttar kontrollen till en botdetekteringsmodul. På så sätt förblir Andel missbruk låg, utan att störa sökmotorerna.
Exempel: Två zoner och mappning av användaragenter
Följande utdrag visar uppdelningen enligt Användaragent och tilldelning av lämpliga gränsvärden. Jag kombinerar detta med differentierade statuskoder och loggningsfält för att kunna mäta effekten på ett tydligt sätt. Botar med generiska agenter hamnar i den strikta zonen. Människor eller verifierade sökrobotar använder den mer flexibla zonen. Denna metod ger förutsägbara Genomströmning per klass:
map $http_user_agent $is_bot {
default 0;
"~*googlebot" 0;
"~*bingbot" 0;
"~*crawler|scraper|bot" 1;
}
limit_req_zone $binary_remote_addr zone=human:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=bot:10m rate=1r/s;
server {
location / {
if ($is_bot) {
limit_req zone=bot burst=5;
}
if ($is_bot = 0) {
limit_req zone=human burst=20 nodelay;
}
limit_req_status 429;
}
}
Felhantering: Att kommunicera 429 på rätt sätt
Hos Limits ger jag ett tydligt Svar med information om när det är lämpligt att göra ett nytt försök. För API:er ingår den giltiga Retry-After-headern, så att klienterna kan tillämpa backoff. Mänskliga användare får en kort förklaring utan tekniska detaljer. Detta minskar antalet supportärenden och säkerställer ett begripligt beteende. En tydlig UX gör gränser acceptabla och förhindrar frustration.
Webbhotell, nätverk och kärna: stärka grunden
Hög legitim trafik och skyddsåtgärder kräver tillförlitliga Resurser och lämpliga standardinställningar på nätverksnivå. Jag ser till att använda aktuella NGINX-versioner, att det finns tillräckligt med RAM-minne för zonerna och att skyddsfunktioner mot transportattacker finns på plats. För att skydda mot SYN-översvämningar hjälper det att aktivera TCP SYN-cookies i kärnan, så att anslutningar inte fastnar. Sammantaget avlastar detta NGINX från onödig belastning. På så sätt fokuserar jag begränsningarna på HTTP-nivåerna och håller Genomströmning stabil.
I korthet: Så här använder jag NGINX:s hastighetsbegränsning på ett effektivt sätt
Jag begränsar förfrågningarna per nyckel, skydda kritiska vägar och håll bots på avstånd med strikta zoner. Burst och nodelay hjälper till att tillåta legitima trafiktoppar utan att främja missbruk. Med hjälp av 429-loggar kalibrerar jag värdena löpande och skärper gränserna endast där det behövs. I kombination med WAF, DDoS-skydd, övervakning och kärnhärdning skapas ett robust skyddskoncept. Den som konsekvent implementerar detta minskar bottrafiken avsevärt och bevarar Prestanda även under belastning.
Komponenter som ofta saknas i praktiken
I många konfigurationer saknas några avgörande komponenter som märkbart ökar effekten av hastighetsbegränsningen:
- Den verkliga klient-IP-adressen bakom proxyservrar: Utan korrekt hantering av Real-IP begränsar NGINX ofta lastbalanseraren IP-adress – begränsningarna gäller då för alla användare som är sammanbundna bakom den.
- Torrtester (Dry-Run): Gränsvärden aktiveras „i blindo“. Det är bättre att i förväg bara registrera hur ofta ett gränsvärde skulle ha trätt i kraft.
- Finkorniga nycklar: Istället för att endast begränsa antalet IP-adresser är det bättre att införa begränsningar per API-token, session eller användare för att öka rättvisan.
- Samverkan med limit_conn: Parallella anslutningar och förfrågningsfrekvenser täcker olika typer av missbruk.
- Särskilda undantag: Hälsokontroller, webhooks eller interna tjänster kräver ofta mindre strikta begränsningar eller inga alls.
Omvänd proxy: säker utvärdering av klientens verkliga IP-adress
Om NGINX ligger bakom en lastbalanserare ställer jag in Real-IP-direktiven så att $binary_remote_addr återspeglar den verkliga klienten. Jag litar bara på nätverk som tillhör mig och aktiverar rekursiv utvärdering:
http {
# Betrodda proxy-IP-intervall (exempel)
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
# Lägg till eventuella offentliga LB-/CDN-intervall
real_ip_header X-Forwarded-For;
real_ip_recursive on;
limit_req_zone $binary_remote_addr zone=perip:20m rate=10r/s;
}
Utan den här inställningen drabbar en begränsning annars oskyldigt många användare samtidigt. Efter konfigurationen kontrollerar jag i åtkomstloggarna om den förväntade klient-IP-adressen dyker upp.
Nyckelstrategi: IP, användare, token och väg
Det valda upplägget avgör hur rättvist och effektivt det blir. Några beprövade modeller:
- Pro IP ($binary_remote_addr): Snabbt klart för användning, lämpligt för /login och anonyma slutpunkter.
- Per API-token: Rättvisa mellan kunderna; skyddar mot NAT-buntning. Jag extraherar token med hjälp av map.
- Per banklass: Begränsa dyra slutpunkter separat, t.ex. /search mer än /status.
map $http_authorization $api_token {
default "";
"~*^Bearer\s+(.+)$" $1;
}
limit_req_zone $api_token zone=per_token:30m rate=5r/s;
server {
location /api/ {
# Gäller endast om ett token finns
limit_req zone=per_token burst=10;
limit_req_status 429;
}
}
Viktigt: Hög nyckelkardinalitet förbrukar minne i zonen. Planera in buffertar och övervaka minnesanvändningen.
Lagring och dimensionering av zonerna
Zonen lagrar metadata för varje aktiv nyckel. Förbrukningen uppgår till några dussin byte per post plus overhead. Av detta drar jag slutsatsen att:
- Om det finns många samtidiga IP-adresser/token väljer jag större zoner, t.ex. 50–100 MB.
- Jag börjar ganska generöst och läser NGINX-loggarna: „shared memory zone is full“ indikerar att det är dags för omskärpning.
- Oanvända nycklar förfaller efter en kort period av inaktivitet; toppvärdena är viktigare än dagsgenomsnittet.
Använda burst och nodelay på ett precist sätt
Utan nodelay NGINX ordnar överskridandena i burst-buffertens ordning och fördröjd Förfrågningar. Med nodelay Tillåtna burst-förfrågningar släpps igenom omedelbart, medan överskottet avvisas. Min metod:
- Interaktiva stigar (HTML): helst utan nodelay, för att skapa korta väntetider istället för ett definitivt 429-fel.
- API:er: ofta med nodelay, så att klienterna tydligt får 429 och tillämpar backoff.
- Dyra slutpunkter: en kort puls för att jämna ut toppar i backend.
Testkörning, loggnivå och utvärdering
Innan jag aktiverar gränsvärdena aktiverar jag Dry-Run och justerar loggnivån. På så sätt kan jag se effekten utan risk:
server {
location /api/ {
limit_req zone=perip burst=20;
limit_req_dry_run on; # endast logga, inte blockera
limit_req_log_level notice; # mindre allvarligt än 'error'
}
}
Därefter analyserar jag åtkomstdata från de senaste 3–7 dagarna, identifierar flaskhalsar, justerar hastighet och burst och inaktiverar först därefter Dry-Run.
429-fel vid överföring: HTML, JSON och Retry-After
För att uppnå en bra användarupplevelse skiljer jag mellan webbläsare och API-klienter och använder Retry-After. Så här kommunicerar jag gränser tydligt:
map $http_accept $wants_json {
default 0;
"~*application/json|/json" 1;
}
server {
error_page 429 = @rate_limited;
location @rate_limited {
add_header Retry-After 2 always;
if ($wants_json) {
add_header Content-Type application/json;
return 429 '{"error":"too_many_requests","retry_after":2}';
}
return 429 "Vänligen försök igen senare.";
}
}
API:er kan på så sätt reagera automatiskt, och användarna får ett tydligt meddelande.
Kombinera limit_req och limit_conn
limit_req anger genomströmning per tidsfönster, limit_conn begränsar antalet samtidiga anslutningar. Mot nedladdningar, chattiga klienter eller HTTP/2-översvämningar kombinerar jag båda metoderna:
limit_conn_zone $binary_remote_addr zone=perip_conn:10m;
server {
location /api/ {
limit_req zone=perip burst=20 nodelay;
limit_conn zone=perip_conn 20; # max. 20 samtidiga anslutningar per IP
}
}
På så sätt förhindrar jag att ett fåtal klienter visserligen håller sig inom gränsen, men ändå tar upp för mycket resurser genom att ha för många parallella anslutningar.
Undantag, hälsokontroller och interna rutter
Inte alla sökvägar behöver begränsningar. Hälsokontroller (/healthz), interna webhooks eller betalningscallbacks tilldelas egna platser utan limit_req – eller med lägre värden:
server {
# inga begränsningar för hälsokontroller
location = /healthz { return 200 "ok"; }
# mjuka begränsningar för betalnings-callbacks
location /webhooks/pay/ {
limit_req zone=perip burst=5;
}
# striktare skydd för inloggning
location = /login {
limit_req zone=perip rate=1r/s burst=3;
}
}
Detaljerade undantag minskar antalet falska positiva resultat och säkerställer stabila integrationer.
Mer robust zonrouting utan ”If-magi”
När det gäller uppdelningen „bot vs. människa“ föredrar jag interna omdirigeringar via namngivna platser. Det gör konfigurationen tydlig och förutsägbar:
map $http_user_agent $is_bot {
default 0;
"~*googlebot|bingbot" 0;
"~*crawler|scraper|bot" 1;
}
limit_req_zone $binary_remote_addr zone=human:20m rate=10r/s;
limit_req_zone $binary_remote_addr zone=bot:10m rate=1r/s;
server {
error_page 418 = @bot;
location / {
if ($is_bot) { return 418; } # intern vidarebefordran
limit_req zone=human burst=20 nodelay;
limit_req_status 429;
try_files $uri $uri/ /index.html;
}
location @bot {
limit_req zone=bot burst=5;
limit_req_status 429;
}
}
På så sätt hamnar botar deterministiskt i den strikta zonen, medan människor hamnar i den avslappnade – utan att båda gränserna gäller samtidigt.
Testa, mäta, prova: en praktisk metod
- Iscensättning: Välj en konservativ inställning för Rate/Burst, aktivera Dry-Run och kör syntetisk belastning mot Hot-Path.
- Rökprov: Skapa korta pulser med curl eller Lasttools och kontrollera 429/fördröjningsbeteendet.
- Produktiv-Pilot: Till att börja med ska man tillämpa detta på enskilda platser och noggrant övervaka loggarna.
- Iterativ skärpning: Sätt endast gränsvärden där mönster upptäcks; minimera antalet falska larm.
# Exempel: snabb burst-test med curl
for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" https://example.com/login & done; wait
Minut- istället för sekundintervall och detaljerade sökvägar
NGINX tillåter intervall i sekunder eller minuter (r/s, r/m). Vid missbruk av inloggningen använder jag ofta 60r/m istället för 1r/s för att tillåta korta, legitima dubbelklick men begränsa kontinuerlig inmatning. Dyra sökvägar får snävare gränser än billiga. Exempel:
limit_req_zone $binary_remote_addr zone=perip_min:20m rate=60r/m;
server {
location /search/ {
limit_req zone=perip_min burst=10; # strängare
}
location /status {
# ingen begränsning – billigt och används internt
return 200;
}
}
Fallgropar och hur jag undviker dem
- Fel nyckel: När jag använder proxyservrar utan riktig IP-adress begränsar jag av misstag alla användare samtidigt.
- För små zoner: „zone is full“ leder till oförutsägbart beteende – dimensionera generöst.
- En gräns för allt: Olika vägar kräver olika värden; en universallösning leder till frustration.
- Ingen övervakning: Utan 429-utvärdering passerar felkonfigurationer obemärkt förbi.
- Över-vitlista: För omfattande undantag öppnar dörren på vid gavel – skapa en vitlista som är målinriktad, tillfällig och överskådlig.
Särdrag med HTTP/2, SSE och cachelagring
HTTP/2 samlar förfrågningar i ett fåtal anslutningar; limit_conn förblir ändå relevant, eftersom strömmar förbrukar resurser. Server-Sent Events eller långa nedladdningar utlöser sällan hastighetsbegränsningar (få förfrågningar), men tar tid i anspråk – här begränsar jag parallellt med limit_conn eller tillämpar bandbreddsstrategier. Där det är möjligt avlastar jag med Caching (t.ex. statiska resurser, frekventa GET-förfrågningar), så att begränsningarna träder i kraft mer sällan och användarna får snabbare svar.
Operativ checklista
- Real-IP korrekt, nycklar definierade (IP/token/användare)
- Zoner med generösa dimensioner, mätvärden/loggar finns tillgängliga
- hastighet/burst anpassad efter vägklass, nodelay medvetet inställt
- Testat med provkörning, 429-kommunikation (Retry-After) implementerad
- Undantag för Health/Webhooks, kombination med limit_conn
- Iterativ omskärpning och larm vid avvikelser


