Perché ogni server esposto a Internet ha bisogno di Fail2ban
Basta controllare i log di autenticazione di un qualunque server Linux raggiungibile da Internet per rendersi conto di un fatto scomodo: nel giro di poche ore compaiono centinaia di tentativi di accesso falliti su SSH, pannelli web o form di login. Non è un attacco mirato: sono scanner automatici che perlustrano di continuo intere sottoreti, alla ricerca di credenziali deboli o servizi mal configurati. Ignorare questo rumore di fondo non è un’opzione, ma bloccare manualmente ogni IP sospetto è impraticabile.
Fail2ban risolve il problema analizzando i log in tempo reale e bannando automaticamente, tramite il firewall, gli indirizzi IP che superano una soglia di tentativi falliti in una finestra temporale configurabile. È uno strumento maturo, leggero, presente nei repository di tutte le principali distribuzioni, ma la configurazione di default lascia molto sul tavolo: un bantime di 10 minuti, tanto per fare un esempio, è quasi inutile contro un attaccante automatizzato che può semplicemente aspettare e riprovare.
In questa guida vediamo come installare, configurare e soprattutto tunare Fail2ban per ottenere una protezione reale, con particolare attenzione agli scenari più comuni su un server di produzione: SSH, Nginx, firewall moderni basati su nftables e persistenza dei ban tra un reboot e l’altro.
I tre concetti chiave: filter, jail, action
Prima di mettere mano alla configurazione conviene avere chiaro il modello concettuale di Fail2ban, perché tutta la configurazione ruota attorno a tre elementi:
- Filter: un insieme di espressioni regolari che individuano le righe di log corrispondenti a un tentativo di accesso fallito.
- Jail: combina un filtro con il percorso del log da monitorare, le soglie di attivazione e l’azione da eseguire al superamento della soglia.
- Action: cosa succede quando la soglia viene superata. Nella maggior parte dei casi è una regola firewall, ma può includere anche l’invio di una notifica via email.
Fail2ban include già filtri e jail pronti per decine di servizi (SSH, Apache, Nginx, Postfix, Dovecot…). Nella pratica quotidiana ci si limita ad abilitare le jail utili e a regolare qualche parametro.
Installazione
Fail2ban è disponibile nei repository ufficiali di tutte le distribuzioni principali.
Debian/Ubuntu:
sudo apt update
sudo apt install fail2ban
Fedora / RHEL 9+ / Rocky / AlmaLinux:
sudo dnf install fail2ban
Arch Linux:
sudo pacman -S fail2ban
Abilitiamo e avviamo il servizio, poi verifichiamo lo stato:
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
Se lo stato non riporta active (running), i log vanno controllati con sudo journalctl -u fail2ban -n 50.
Configurare Fail2ban nel modo corretto
Un errore comune è modificare direttamente /etc/fail2ban/jail.conf: questo file viene sovrascritto a ogni aggiornamento del pacchetto, con conseguente perdita delle personalizzazioni. L’approccio corretto è creare un file dedicato dentro jail.d/:
sudo nano /etc/fail2ban/jail.d/custom.conf
In alternativa si può copiare il file di default in jail.local, che ha priorità sui valori in jail.conf:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
La sezione [DEFAULT]
Nella sezione [DEFAULT] si impostano i valori applicati a tutte le jail, salvo override specifico:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
bantime: durata del ban. Il default (spesso 10 minuti) è troppo permissivo: 1 ora è un buon punto di partenza, e per attaccanti persistenti si può salire a24ho1w. Il valore-1produce un ban permanente, da usare con cautela.findtime: la finestra temporale in cui vengono contati i fallimenti.maxretry: numero di tentativi falliti prima del ban. 5 è ragionevole per SSH, si può scendere a 3 per una postura più aggressiva.ignoreip: gli IP che non verranno mai bannati. È fondamentale aggiungere qui il proprio IP prima di abilitare qualsiasi jail: restare fuori dal proprio server per un ban accidentale è un classico errore da evitare.
Se il server ha un indirizzo IPv6 pubblico, va incluso anche quello: alcuni filtri più datati intercettano solo IPv4, quindi conviene verificare che le jail catturino correttamente entrambi i protocolli.
La jail SSH
È la jail più importante per la maggior parte dei server. In jail.local o in un nuovo file /etc/fail2ban/jail.d/sshd.conf:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 1h
Se SSH è stato spostato su una porta non standard (buona pratica consigliata), va aggiornata la riga port. Sui sistemi basati su systemd, %(sshd_log)s punta automaticamente al journal; sui sistemi più datati che usano /var/log/auth.log o /var/log/secure, Fail2ban gestisce la differenza tramite il parametro backend. Dopo ogni modifica alla configurazione:
sudo fail2ban-client reload
Jail per Nginx
I server web attirano un tipo diverso di abuso: scanner di URL 404, bruteforcer su form di login, bot che generano richieste inutili.
[nginx-http-auth]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 3
[nginx-limit-req]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 10
La jail nginx-limit-req intercetta i client che superano i limit_req configurati in Nginx: è una combinazione efficace se il server web è già stato ottimizzato per gestire traffico elevato. Se Fail2ban segnala che un percorso di log non esiste, va impostato esplicitamente, ad esempio logpath = /var/log/nginx/error.log.
Verificare jail e ban attivi
Il comando fail2ban-client è lo strumento principale per monitorare la situazione. Elenco delle jail attive:
sudo fail2ban-client status
Dettaglio di una jail specifica, comprensivo di IP attualmente bannati:
sudo fail2ban-client status sshd
Per bannare o sbannare manualmente un IP:
sudo fail2ban-client set sshd banip 203.0.113.99
sudo fail2ban-client set sshd unbanip 203.0.113.99
Il comando unbanip è quello da tenere a portata di mano nel caso in cui ci si banni da soli per errore, prima di aver aggiunto il proprio IP a ignoreip.
Ban incrementali con la jail recidive
Una delle funzionalità meno conosciute ma più efficaci di Fail2ban è la jail recidive, che monitora il log interno di Fail2ban stesso e applica ban molto più lunghi agli IP che, dopo la scadenza di un primo ban, tornano a fare bruteforcing.
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
action = %(action_mwl)s
bantime = 1w
findtime = 1d
maxretry = 5
Con questa configurazione, un IP bannato 5 volte in un giorno riceve un ban di una settimana: è l’equivalente più vicino a una blocklist persistente senza dover integrare feed di threat intelligence esterni. Su sistemi che scrivono solo sul journal, va impostato backend = systemd nella jail recidive, oppure va verificato che Fail2ban stia scrivendo un log tradizionale.
Testare i filtri prima di attivarli
Prima di abilitare una jail, conviene verificare che il regex del filtro corrisponda davvero alle righe di log presenti sul sistema:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
L’output riporta gli IP individuati e il numero di righe che hanno fatto match. Un filtro che non intercetta nulla non protegge nulla: questo comando è indispensabile soprattutto quando si scrive un filtro personalizzato per un’applicazione custom, dentro /etc/fail2ban/filter.d/:
# /etc/fail2ban/filter.d/myapp-auth.conf
[Definition]
failregex = ^<HOST> .* "POST /login" 401
ignoreregex =
Il tag <HOST> è obbligatorio: Fail2ban lo sostituisce con un’espressione regolare che cattura l’indirizzo IP da bannare. Un pattern troppo generico rischia di bannare traffico legittimo, quindi va sempre validato con fail2ban-regex prima di collegarlo a una jail attiva.
nftables, firewalld e persistenza dei ban
Su Debian 12+ e Ubuntu 22.04+, nftables è il backend firewall di default. L’azione di ban predefinita di Fail2ban usa ancora iptables, che nella maggior parte delle installazioni funziona tramite il layer di compatibilità iptables-nft. Se invece si usa nftables puro, l’azione va impostata esplicitamente:
banaction = nftables-multiport
banaction_allports = nftables-allports
Su RHEL, Fedora e Rocky, dove firewalld è lo standard, va usata l’azione corrispondente:
banaction = firewallcmd-rich-rules
banaction_allports = firewallcmd-allports
Per default, i ban sono mantenuti in memoria e vengono persi a ogni riavvio. Per farli sopravvivere ai reboot va abilitato il database SQLite (su molte distribuzioni recenti è già attivo di default):
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 7d
Una configurazione di partenza completa
Ecco un file /etc/fail2ban/jail.d/custom.conf che copre i casi d’uso più comuni su un server Linux tipico, da usare come punto di partenza:
[DEFAULT]
bantime = 2h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1
dbfile = /var/lib/fail2ban/fail2ban.sqlite3
dbpurgeage = 7d
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 6h
[nginx-http-auth]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 4
[nginx-limit-req]
enabled = true
logpath = %(nginx_error_log)s
maxretry = 10
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5
sudo fail2ban-client reload
sudo fail2ban-client status
Cosa Fail2ban non risolve
Fail2ban è uno strumento reattivo, non preventivo: banna un IP solo dopo che ha già effettuato diversi tentativi. Non copre, da solo, alcuni scenari:
- attacchi bruteforce distribuiti su migliaia di IP diversi, ciascuno con uno o due tentativi soltanto;
- exploit zero-day che non generano righe di log riconoscibili;
- attacchi a livello applicativo che non producono un fallimento di autenticazione tracciabile.
Per una protezione a più livelli, Fail2ban va affiancato all’autenticazione SSH tramite chiavi (disabilitando del tutto l’autenticazione via password), a un firewall configurato correttamente e a una revisione periodica dei log. Un’attenzione particolare va riservata ai server dietro Cloudflare o un altro reverse proxy: senza ripristinare l’IP originale del visitatore (tramite mod_remoteip su Apache o real_ip_module su Nginx), Fail2ban finirebbe per bannare gli IP del proxy stesso invece degli attaccanti reali.
Comandi da tenere sempre a portata di mano
sudo fail2ban-client status— elenco di tutte le jail attivesudo fail2ban-client status sshd— stato dettagliato di una jailsudo fail2ban-client set sshd banip 1.2.3.4— ban manuale di un IPsudo fail2ban-client set sshd unbanip 1.2.3.4— rimozione manuale di un bansudo fail2ban-client reload— ricarica la configurazione dopo una modificasudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf— test di un filtrosudo tail -f /var/log/fail2ban.log— monitoraggio dei ban in tempo reale
Conclusione
Fail2ban resta uno degli strumenti che meritano un posto fisso su ogni server Linux esposto a Internet: l’installazione richiede pochi minuti e già con una configurazione minima riduce in modo drastico il rumore generato da scanner SSH e probe automatizzati sui servizi web. La differenza reale, però, la fanno tre accorgimenti spesso trascurati: impostare un bantime ragionevole (il default di 10 minuti è quasi inutile), aggiungere sempre il proprio IP a ignoreip prima di abilitare le jail, e attivare la jail recidive per penalizzare chi insiste. Da soli, questi tre passaggi fanno la differenza tra un’installazione di default e una protezione che funziona davvero.
Fonte: Fail2ban on Linux: Protect Your Server from Brute-Force Attacks, LinuxBlog.io