Vai al contenuto
EuroVPSEuroVPS

Limitate il percorso costoso, non il crawler

Trovate gli URL che costano lavoro reale al vostro sito, poi limitate lì i crawler con le stick table di HAProxy e un 429, senza danneggiare la ricerca o i visitatori.

Di EuroVPS Engineering

5 min di lettura
Limitate il percorso costoso, non il crawler

Bloccare i bot è facile e di solito sbagliato. I motori di ricerca vi portano visitatori, le anteprime dei link vi portano clic, e persino i crawler AI più aggressivi sono spesso traffico che preferireste rallentare piuttosto che chiudere fuori. L'approccio migliore è trovare dove i crawler vi costano davvero denaro, cioè una manciata di percorsi non in cache e pesanti sul database, e controllare lì il ritmo, al load balancer. Ecco come lo facciamo.

Scoprite cosa è costoso prima di scrivere una regola

Il costo vive sui percorsi che mancano la cache e arrivano a PHP e al database: sitemap generate al volo, ricerca, navigazione a faccette dove ogni combinazione di filtri è una query nuova, e qualunque cosa con una query string che la cache non conosce.

Il vostro access log vi dice già quali sono. Se il log registra il tempo di richiesta (il $request_time di nginx, per esempio, come ultimo campo), sommate il tempo speso per percorso:

awk '{split($7, p, "?"); t[p[1]] += $NF; n[p[1]]++}
     END {for (u in t) printf "%10.1f s %8d req  %s\n", t[u], n[u], u}' access.log \
  | sort -rn | head -20

Poi guardate chi lo sta spendendo, per user agent, su quei percorsi:

awk -F'"' '$2 ~ /sitemap|search|filter=/ {print $6}' access.log \
  | sort | uniq -c | sort -rn | head -20

Due elenchi, il lavoro di una sera, e sapete esattamente dove una regola renderà.

Rate limit con le stick table di HAProxy

HAProxy può contare i ritmi di richiesta per client e per user agent in memoria, a velocità di linea, e agire di conseguenza. Una configurazione minima che protegge solo i percorsi costosi:

backend st_src
    stick-table type ipv6 size 200k expire 10m store http_req_rate(10s)

backend st_ua
    stick-table type string len 128 size 20k expire 10m store http_req_rate(10s)

frontend fe_web
    # bind lines and certificates as usual
    acl expensive path_beg /sitemap /search
    acl expensive url_sub -i filter=
    http-request track-sc0 src table st_src if expensive
    http-request track-sc1 req.fhdr(user-agent) table st_ua if expensive
    http-request deny deny_status 429 hdr Retry-After 60 if expensive { sc_http_req_rate(0) gt 20 }
    http-request deny deny_status 429 hdr Retry-After 60 if expensive { sc_http_req_rate(1) gt 60 }

Tre scelte di progetto contano qui. Vengono tracciati solo i percorsi costosi, quindi nient'altro sul sito viene toccato. La risposta è un 429 con un header Retry-After, che i crawler ben educati interpretano come «rallenta e torna dopo», non come un errore per cui punirvi. E la seconda tabella conta per user agent, il che cattura un crawler distribuito su molti indirizzi che passerebbe sotto un limite per indirizzo. Le soglie qui sopra sono segnaposto: impostate le vostre in base a ciò che il percorso può davvero servire senza cache.

Identificate i crawler con cura

Confrontate gli user agent in modo lasco

I crawler cambiano il formato delle loro stringhe user agent, aggiungendo token di versione, URL o nuovi nomi di prodotto. Una regola che confronta esattamente l'intera stringa smette di funzionare il giorno in cui cambia. Il confronto per sottostringa sulla parte stabile (hdr_sub(user-agent) -i <name>) continua a funzionare.

Non bloccate il motore di ricerca per sbaglio

Verificate un crawler prima di trattarlo in modo speciale. I principali motori di ricerca pubblicano come farlo: una ricerca DNS inversa sull'indirizzo del client dovrebbe restituire un hostname nel loro dominio, e una ricerca diretta su quell'hostname dovrebbe restituire lo stesso indirizzo.

host <client-address>        # should return a name in the engine's published domain
host <name-returned-above>   # should return the same client address

I crawler genuini vengono poi limitati sui percorsi costosi come tutti gli altri, e continuano a scansionare liberamente il resto del sito. Gli impostori non ricevono favori.

Rifiutate le forme che non sono mai legittime

Alcuni pattern di richiesta non hanno alcun uso legittimo: URL ricodificati più e più volte fino a diventare lunghi migliaia di caratteri, combinazioni impossibili di parametri, la stessa codifica percentuale applicata tre volte. Una singola regola al bordo li rifiuta prima che costino qualcosa:

http-request deny deny_status 400 if { url_sub -i %2525 }

Adattate il pattern a ciò che mostrano i vostri log. Il punto è che il load balancer è il posto più economico dello stack per dire di no.

Proteggete PHP da ciò che passa

Nessuna regola al bordo è perfetta, quindi il livello applicativo ha bisogno dei propri limiti. In ogni pool PHP-FPM, un timeout di terminazione impedisce a una richiesta patologica di tenere un worker per minuti, e un tetto di memoria le impedisce di crescere senza limiti:

request_terminate_timeout = 60s
php_admin_value[memory_limit] = 256M
pm.max_requests = 500

Impostateli insieme alle regole al bordo, così i due livelli concordano su cosa sia una richiesta ragionevole. Nel frattempo Varnish continua a servire le pagine in cache, così lettori e acquirenti non percepiscono nulla di tutto questo.

Come lo gestiamo noi

Sulle proprietà di news ed e-commerce che gestiamo, i percorsi di sitemap, ricerca e listati filtrati ricevono protezioni di ritmo dal primo giorno, dimensionate su ciò che ogni sito può servire senza cache. Le nuove regole si scrivono dagli access log, si distribuiscono su ogni edge della proprietà, e si registrano con i numeri prima e dopo per il cliente. Quando compare un nuovo crawler, una regola mirata può di solito essere attiva su ogni edge entro pochi minuti dall'identificazione del pattern.

Controllate il vostro edge

  • Quali cinque percorsi sono costati più tempo di PHP e database la settimana scorsa?
  • Chi li ha richiesti, per user agent?
  • I vostri limiti si applicano solo dove sta il costo, o all'intero sito?
  • Rispondete con 429 e Retry-After, o con un blocco?
  • Quando qualcuno ha confermato l'ultima volta che le regole corrispondono ancora al traffico reale?

Se i crawler vi stanno mangiando la capacità, possiamo leggere i vostri log con voi e scrivere le regole.

cta: Parla con un ingegnere

Related

  • /what-we-do/operations/edge-traffic-control/
  • /what-we-do/data-web/high-availability-web-tiers/
  • /what-we-do/data-web/performance-audits/

Pubblicato il 12 ottobre 2026.

Tutte le note dal campo