Questo articolo esiste anche in inglese: Fail2ban Not Banning IPs (EN).
La guida Fail2ban copre installazione e configurazione di base su Linux. Il problema descritto qui è diverso e più insidioso: fail2ban è installato, il jail sembra attivo (fail2ban-client status <jail> mostra tentativi rilevati), ma gli IP non vengono mai bannati, oppure vengono bannati IP che non sono l'attaccante reale.
Il sintomo, prima di tutto
Se il sito è dietro un reverse proxy nginx o un CDN come Cloudflare, il caso più comune è questo: nel log di accesso nginx, il campo IP di ogni riga non è l'IP del visitatore reale, ma quello del proxy o dell'edge del CDN che ha inoltrato la richiesta. Fail2ban legge quel log, estrae quell'IP con il proprio filtro regex, e alla fine banna (o prova a bannare) l'IP sbagliato: il proxy stesso, non l'attaccante.
Distinguere "IP visto dall'app" da "punto di enforcement"
Ci sono due concetti diversi che vanno tenuti separati:
- L'IP visto dall'applicazione/dal log: è quello che fail2ban analizza per decidere chi bannare. Se è sbagliato (l'IP del proxy invece di quello del client reale), tutto il resto della configurazione è inutile.
- Il punto di enforcement del ban: è dove il ban viene effettivamente applicato - tipicamente
iptables/nftablessul server che esegue fail2ban. Se il traffico arriva già filtrato/instradato da un CDN esterno (come Cloudflare), bannare l'IP a livello di iptables locale non impedisce all'edge del CDN di continuare a inoltrare le richieste: serve un meccanismo diverso, come un'azione fail2ban che chiama l'API del CDN.
Verifica passo per passo
1. Cosa c'è nel log che fail2ban legge
tail -n 20 /var/log/nginx/access.log
Se ogni riga mostra lo stesso IP (o un piccolo insieme di IP), quasi certamente è l'IP del reverse proxy o del CDN, non dei singoli visitatori.
2. nginx sta riscrivendo l'IP reale?
Il modulo ngx_http_realip_module di nginx riscrive $remote_addr con l'IP reale del client, leggendolo da un header inoltrato da un proxy fidato. Configurazione tipica dietro Cloudflare:
# Elenco reale degli IP Cloudflare da mantenere aggiornato
# (https://www.cloudflare.com/ips/), qui abbreviato per esempio
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;
Senza questa configurazione (o l'equivalente per un reverse proxy interno, con X-Forwarded-For e set_real_ip_from sull'IP del proxy stesso), $remote_addr nel log resta l'IP del proxy, non del client, indipendentemente da cosa fa fail2ban a valle.
3. Il filtro fail2ban corrisponde al formato del log?
Verificare che il filtro (es. /etc/fail2ban/filter.d/nginx-http-auth.conf o un filtro personalizzato) usi il campo del log realmente popolato con l'IP corretto - se real_ip_header non è configurato, nessun filtro fail2ban, per quanto scritto bene, può recuperare l'IP reale: quel dato semplicemente non è nel log.
Test diretto del filtro su un log reale, senza aspettare un attacco vero:
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nome-filtro.conf
4. Il ban viene applicato?
fail2ban-client status nome-jail
iptables -L -n | grep f2b
Se il jail mostra IP "banned" ma la regola iptables/nftables corrispondente non esiste o non blocca nulla, il problema è nell'azione di ban (action nel file .local del jail), non nel filtro.
Il caso specifico di Cloudflare
Se il sito è dietro Cloudflare (proxy attivo, non solo DNS), bannare un IP a livello di iptables sul server d'origine blocca quella richiesta solo se e quando riesce ad arrivare al server: molte varianti di attacco (scraping aggressivo, tentativi di login) passano comunque attraverso l'edge Cloudflare, che non è influenzato dal ban locale. In questi casi serve un'azione fail2ban dedicata che chiama l'API di Cloudflare per bloccare l'IP a livello di edge, non (solo) iptables locale.
Domande frequenti (FAQ)
Fail2ban dice "already banned" ma l'attacco continua: perché?
Quasi sempre perché l'IP bannato è quello del proxy/CDN, non dell'attaccante reale: il ban è tecnicamente attivo, ma sta bloccando un indirizzo che non ha alcun effetto sul traffico in arrivo.
Serve fail2ban se uso già Cloudflare con le sue protezioni?
Le protezioni di Cloudflare (rate limiting, WAF) operano a livello di edge e sono complementari, non sostitutive: fail2ban resta utile per pattern specifici dell'applicazione (es. tentativi di login falliti) che Cloudflare non necessariamente riconosce come tali.
Come verifico l'elenco aggiornato degli IP Cloudflare da usare in set_real_ip_from?
Cloudflare pubblica l'elenco ufficiale e aggiornato su cloudflare.com/ips: va tenuto sincronizzato, idealmente con uno script schedulato, perché gli intervalli possono cambiare.
Per la parte di hardening lato WordPress/nginx spesso collegata a questo stesso tipo di attacchi, vedi anche WordPress password reset brute force: analisi di un attacco reale e contromisure nginx.