Fail2ban: configuración de la protección de SSH contra fuerza bruta
Fail2ban lee los registros de los servicios, detecta intentos de acceso fallidos repetidos y bloquea temporalmente la IP del atacante a través del firewall. Para proteger SSH basta con instalar el paquete, crear /etc/fail2ban/jail.local con la sección [sshd] (enabled = true, maxretry, findtime, bantime) y reiniciar el servicio; el estado se comprueba con fail2ban-client status sshd.
Fail2ban es un demonio que vigila los registros de los servicios, detecta los intentos de acceso fallidos repetidos y bloquea durante un tiempo la dirección IP desde la que llegan. Para SSH es la protección más sencilla contra la adivinación de contraseñas: los bots dejan de insistir tras unos pocos errores. A continuación tiene la configuración de fail2ban desde la instalación hasta la comprobación de los baneos y los errores típicos.
Para qué sirve fail2ban si ya hay claves SSH
Cualquier servidor con el puerto 22 abierto empieza a recibir intentos de acceso de bots pocos minutos después de arrancar. Compruébelo usted mismo:
$ sudo journalctl -u ssh --since "1 hour ago" | grep -c "Failed password"
412
Si el acceso por contraseña está desactivado y solo se usan claves, adivinar el acceso es prácticamente imposible. Pero fail2ban sigue siendo útil: reduce el ruido en los registros, disminuye la carga por miles de conexiones y protege frente a errores de configuración, como cuando el acceso por contraseña se deja activado sin querer. Es una segunda capa de defensa, no un sustituto de las claves.
Cómo funciona fail2ban
La lógica tiene tres partes:
- Filtro (filter) — conjunto de expresiones regulares que encuentran en el registro las líneas de intento fallido y extraen de ellas la IP. Los filtros están en
/etc/fail2ban/filter.d/. - Acción (action) — qué hacer con el infractor: añadir una regla en iptables, nftables, ufw o firewalld. Las acciones están en
/etc/fail2ban/action.d/. - Celda (jail) — la combinación de filtro, acción, origen de los registros y umbrales. Por ejemplo, la celda
sshdvigila el registro de SSH.
Si desde una IP se acumulan maxretry coincidencias durante el tiempo findtime, la dirección se bloquea durante bantime. Al terminar ese plazo, el bloqueo se levanta automáticamente.
Instalación de fail2ban
En Debian y Ubuntu:
sudo apt update
sudo apt install fail2ban
En RHEL, Rocky y AlmaLinux el paquete está en el repositorio EPEL:
sudo dnf install epel-release
sudo dnf install fail2ban
Active el arranque automático y compruebe el estado del servicio:
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
En Debian y Ubuntu la celda de SSH ya viene activada por defecto mediante /etc/fail2ban/jail.d/defaults-debian.conf. En la familia RHEL, tras la instalación no hay nada activado: las celdas hay que habilitarlas a mano.
Dónde se guardan los ajustes: jail.conf y jail.local
El archivo principal es /etc/fail2ban/jail.conf, pero no conviene editarlo: al actualizar el paquete se sobrescribirá. Los ajustes propios se colocan en /etc/fail2ban/jail.local o en archivos separados /etc/fail2ban/jail.d/*.local. Fail2ban lee los archivos en este orden, y cada uno posterior sobrescribe al anterior:
jail.confjail.d/*.confjail.localjail.d/*.local
No copie todo jail.conf en jail.local: así congelará los valores por defecto antiguos. En jail.local se escribe solo lo que se cambia.
Configuración de fail2ban para SSH: jail.local mínimo
Cree el archivo:
sudo nano /etc/fail2ban/jail.local
y añada en él:
[DEFAULT]
# Mis direcciones, que nunca se deben bloquear
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
bantime = 1h
findtime = 10m
maxretry = 5
# De dónde leer los registros: diario de systemd o archivos
backend = systemd
[sshd]
enabled = true
port = ssh
maxretry = 3
Reinicie el servicio y compruebe que la celda está activa:
$ sudo systemctl restart fail2ban
$ sudo fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
Qué significan los parámetros
| Parámetro | Significado | Ejemplo |
|---|---|---|
enabled | si la celda está activa | true |
port | puerto(s) que bloquear para el infractor | ssh, 2222, ssh,2222 |
maxretry | cuántos errores se admiten antes del baneo | 3 |
findtime | ventana en la que se cuentan los errores | 10m |
bantime | duración del baneo; -1 — para siempre | 1h, 1d |
ignoreip | direcciones y subredes que nunca se bloquean | 10.0.0.0/8 |
backend | origen de los registros | systemd, auto |
logpath | ruta del archivo de registro con backend de archivo | /var/log/auth.log |
banaction | con qué firewall bloquear | nftables-multiport, ufw |
Los tiempos pueden escribirse con sufijos: s, m, h, d, w. Los números sin sufijo se interpretan como segundos.
backend: systemd o archivo
En Debian 12 y Ubuntu 24.04 actuales puede que no exista el archivo /var/log/auth.log si rsyslog no está instalado: los registros de SSH viven solo en el diario de systemd. Entonces hace falta backend = systemd; de lo contrario, fail2ban no arrancará con un error de que no encuentra el archivo de registro. Si rsyslog está instalado, puede usar la variante con archivo:
[sshd]
enabled = true
backend = auto
logpath = /var/log/auth.log
En los sistemas RHEL el archivo equivalente es /var/log/secure.
SSH en un puerto no estándar
Si sshd escucha, por ejemplo, en el puerto 2222, indíquelo en la celda; si no, fail2ban bloqueará el puerto 22 y el ataque continuará por el 2222:
[sshd]
enabled = true
port = 2222
Para bloquear al infractor en todos los puertos a la vez se puede usar la acción iptables-allports o nftables-allports mediante el parámetro banaction.
Elegir el firewall: iptables, nftables, ufw, firewalld
Por defecto, en Debian se usa banaction = nftables (en versiones antiguas, iptables), y en RHEL, firewalld. Si el servidor tiene ufw configurado, es más cómodo que los baneos se vean en él:
[DEFAULT]
banaction = ufw
Para firewalld:
[DEFAULT]
banaction = firewallcmd-rich-rules
Para comprobar que las reglas aparecen de verdad, use sudo nft list ruleset | grep f2b o sudo iptables -L -n | grep f2b: fail2ban crea cadenas con el prefijo f2b-.
Cómo comprobar el funcionamiento: fail2ban-client status
La herramienta principal de gestión es fail2ban-client. Estado de una celda concreta:
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 2
| |- Total failed: 147
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 4
|- Total banned: 38
`- Banned IP list: 45.148.10.12 92.118.39.7 185.224.128.40 218.92.0.112
Aquí se ve cuántos errores hay ahora en la ventana, cuántas IP están bloqueadas y cuáles son. Para probar la protección en vivo, intente entrar varias veces con una contraseña incorrecta desde otra máquina (no desde una que esté en ignoreip): tras el tercer intento la conexión dejará de establecerse.
El registro del propio fail2ban está en /var/log/fail2ban.log:
$ sudo tail -n 3 /var/log/fail2ban.log
2026-10-14 09:12:41,118 fail2ban.filter [812]: INFO [sshd] Found 218.92.0.112
2026-10-14 09:12:44,302 fail2ban.filter [812]: INFO [sshd] Found 218.92.0.112
2026-10-14 09:12:47,551 fail2ban.actions [812]: NOTICE [sshd] Ban 218.92.0.112
Cómo desbanear una IP en fail2ban
Si se bloqueó a sí mismo o a un compañero, levante el bloqueo desde la consola del servidor (mediante el panel del proveedor o desde otra IP):
sudo fail2ban-client set sshd unbanip 203.0.113.25
Para quitar todos los baneos de todas las celdas:
sudo fail2ban-client unban --all
Para bloquear una dirección a mano, sin esperar a que el filtro actúe:
sudo fail2ban-client set sshd banip 198.51.100.7
Para que no se repita, añada sus direcciones fijas o la subred de la oficina a ignoreip.
Baneo creciente para reincidentes
Muchos bots vuelven en cuanto se levanta su bloqueo. Desde la versión 0.11 fail2ban puede aumentar el plazo del baneo para los reincidentes:
[DEFAULT]
bantime = 1h
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 4w
Cada nuevo baneo de la misma IP será más largo que el anterior, pero no más de cuatro semanas. Como alternativa para versiones antiguas está la celda recidive, que lee el registro del propio fail2ban y bloquea durante mucho tiempo las direcciones que aparecen varias veces:
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5
Comprobación del filtro: fail2ban-regex
Si la celda funciona pero no banea a nadie, compruebe que el filtro encuentra líneas en el registro. Para un registro en archivo:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
Para el diario de systemd:
sudo fail2ban-regex systemd-journal sshd
En la salida busque la línea Lines: ... matched. Cero coincidencias significa que el filtro no se ajusta al formato de los registros o que se indicó otro origen. Antes de reiniciar conviene comprobar la sintaxis de toda la configuración:
sudo fail2ban-client -t
Errores habituales
- El servicio no arranca: «Have not found any log file for sshd jail». No existe
/var/log/auth.log. Pongabackend = systemdo instale rsyslog. - Hay baneos en el estado, pero el ataque continúa. Se indicó otro puerto (SSH se movió) o las reglas del firewall quedan tapadas por una regla de permiso anterior. Revise
porty la salida denft list ruleset. - Los cambios no se aplicaron. Se editó
jail.conf, pero enjail.localo enjail.d/*.localhay otro valor. Vea el valor final:sudo fail2ban-client get sshd maxretry. - Se bloqueó a sí mismo. Desbanee desde la consola y añada la IP a
ignoreip. - Fail2ban en Docker no ve los ataques. Los puertos de los contenedores se publican mediante la cadena DOCKER, que se salta INPUT. Para esos servicios use
chain = DOCKER-USERen la acción.
Qué más hacer para proteger SSH
Fail2ban funciona bien junto con medidas básicas en /etc/ssh/sshd_config:
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
Después de cambiarlo, compruebe la configuración con sudo sshd -t y reinicie el servicio. No cierre la sesión actual hasta confirmar en una nueva que el acceso con clave funciona. Además, puede limitar el acceso a SSH en el firewall solo a las direcciones necesarias.
Resumen
Configurar fail2ban se reduce a unos pocos pasos: instalar el paquete, crear jail.local con la sección [sshd], elegir el backend y el puerto correctos, fijar maxretry, findtime y bantime, añadir sus direcciones a ignoreip y comprobar el funcionamiento con fail2ban-client status sshd. Junto con el acceso solo por claves, esto protege SSH de forma fiable frente a la adivinación de contraseñas. La protección del servidor y fail2ban se explican con práctica en el curso de Linux.
Preguntas frecuentes
¿Hace falta fail2ban si el acceso por contraseña está desactivado?
No es obligatorio, pero es útil: elimina miles de intentos basura de los registros, reduce la carga y sirve de respaldo si alguien vuelve a activar el acceso por contraseña por error.
¿Cómo ver todas las IP bloqueadas en todas las celdas?
Ejecute sudo fail2ban-client banned: el comando muestra las listas de direcciones bloqueadas por cada celda. Para una sola celda use fail2ban-client status sshd.
¿Se conservan los baneos tras reiniciar el servidor?
Sí, fail2ban guarda los baneos en su base SQLite (/var/lib/fail2ban/fail2ban.sqlite3) y restaura los bloqueos vigentes al arrancar, salvo que el parámetro dbpurgeage los haya eliminado antes.
¿Se puede proteger con fail2ban algo más que SSH?
Sí, incluye filtros para nginx, Apache, Postfix, Dovecot y otros servicios. Basta con activar la celda correspondiente en jail.local, por ejemplo [nginx-http-auth] con enabled = true.
¿En qué se diferencia fail2ban de una restricción en el firewall?
El firewall permite o prohíbe direcciones de forma estática, mientras que fail2ban bloquea dinámicamente a quien se ha comportado mal según los registros. A menudo se combinan: lista blanca en el firewall y fail2ban para el resto.
Este tema se explica a fondo y con práctica en el curso «Linux: с нуля до уверенного администрирования».
Ir al curso