Instalar y configurar Fail2Ban en un VPS Linux
Configure Fail2Ban para bloquear ataques de fuerza bruta en SSH y Nginx. Cubre acciones de baneo con UFW y nftables, jails personalizadas, escalamiento recidive y pruebas de filtros en Ubuntu 24.04 y Debian 12.
Fail2Ban vigila sus archivos de log en busca de fallos de autenticación repetidos y bloquea las direcciones IP infractoras a través de su firewall. Detiene los ataques de fuerza bruta antes de que tengan éxito. Un VPS recién desplegado suele recibir intentos de conexión SSH en cuestión de minutos. Fail2Ban es la defensa estándar.
Esta guía cubre la instalación en Ubuntu 24.04 y Debian 12, la configuración de jails para SSH y Nginx, ambos backends de acción de baneo (UFW y nftables), la jail recidive para reincidentes, y las pruebas de filtros con fail2ban-regex. Cada cambio de configuración incluye un paso de verificación.
Requisitos previos: Un VPS con Ubuntu 24.04 o Debian 12 con acceso root o sudo. Su firewall ya debe estar activo y SSH debe estar asegurado. Esta guía forma parte de la serie seguridad VPS Linux.
¿Cómo instalo Fail2Ban en Ubuntu 24.04 y Debian 12?
Instale Fail2Ban con apt. El paquete está en los repositorios por defecto de ambas distribuciones. Ubuntu 24.04 incluye la versión 1.0.2, al igual que Debian 12. En Debian 12, también necesita python3-systemd para que Fail2Ban pueda leer el journal de systemd.
sudo apt update && sudo apt install -y fail2ban
En Debian 12, instale los bindings de Python para systemd:
sudo apt install -y python3-systemd
Habilite e inicie el servicio:
sudo systemctl enable --now fail2ban
El flag enable hace que Fail2Ban se inicie en el arranque. El flag --now lo inicia de inmediato. Verifique que está funcionando:
sudo systemctl status fail2ban
Debería ver Active: active (running) en la salida. Si el estado muestra failed, consulte el journal:
journalctl -u fail2ban -n 20 --no-pager
¿Cuál es la diferencia entre jail.conf, jail.local y jail.d/?
jail.conf es el archivo de configuración por defecto incluido con el paquete. Las actualizaciones del paquete lo sobrescriben. Nunca edite jail.conf directamente. Sus cambios desaparecerán en el próximo apt upgrade.
jail.local es el archivo de sobreescritura tradicional. Fail2Ban lee primero jail.conf y luego aplica los ajustes de jail.local por encima. Funciona, pero el archivo crece hasta convertirse en un monolito difícil de mantener.
El directorio jail.d/ es el mejor enfoque. Coloque un archivo .conf por jail. Fail2Ban los carga en orden alfabético después de jail.conf y jail.local. Cada servicio queda aislado y es fácil añadir o eliminar jails sin tocar otras configuraciones.
Esta guía usa archivos drop-in en jail.d/. Compruebe que el directorio existe:
ls /etc/fail2ban/jail.d/
Ya debería existir. Si ve archivos como defaults-debian.conf, es normal. En Ubuntu 24.04, este archivo habilita la jail sshd y establece banaction = nftables como acción de baneo por defecto. En Debian 12, habilita la jail sshd. Como Fail2Ban carga los archivos de jail.d/ en orden alfabético, cualquier archivo de configuración por defecto personalizado debe ordenarse después de defaults-debian.conf para sobreescribir sus ajustes. Esta guía usa zz-defaults.conf por esa razón.
¿Cómo configuro la jail SSH en Fail2Ban?
La jail SSH monitoriza los logs de autenticación y banea las IP que fallan demasiadas veces al iniciar sesión. En Ubuntu 24.04 y Debian 12, la jail sshd está habilitada por defecto a través de /etc/fail2ban/jail.d/defaults-debian.conf. Pero los valores por defecto son permisivos (5 reintentos, baneo de 10 minutos). Ajústelos.
Cree una configuración drop-in:
sudo tee /etc/fail2ban/jail.d/sshd.conf > /dev/null << 'EOF'
[sshd]
enabled = true
mode = aggressive
port = ssh
backend = systemd
maxretry = 3
findtime = 600
bantime = 3600
EOF
Significado de cada parámetro:
| Parámetro | Valor | Significado |
|---|---|---|
enabled |
true |
Activa esta jail |
mode |
aggressive |
Detecta más patrones de fallo SSH, incluyendo fallos de autenticación por clave |
port |
ssh |
Monitoriza el puerto SSH (se resuelve a 22, o su puerto personalizado) |
backend |
systemd |
Lee del journal de systemd en lugar de archivos de log |
maxretry |
3 |
Banea después de 3 intentos fallidos |
findtime |
600 |
Cuenta fallos en una ventana de 10 minutos |
bantime |
3600 |
Banea durante 1 hora (3600 segundos) |
Si cambió su puerto SSH (debería hacerlo), reemplace ssh por su número de puerto:
port = 2222
Reinicie Fail2Ban para aplicar los cambios:
sudo systemctl restart fail2ban
Verifique que la jail está activa:
sudo fail2ban-client status sshd
Salida esperada:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 0
| `- Journal matches: _SYSTEMD_UNIT=sshd.service + _COMM=sshd
`- Actions
|- Currently banned: 0
|- Total banned: 0
`- Banned IP list:
Fíjese bien: la línea Journal matches confirma que Fail2Ban lee del journal de systemd, no de un archivo de log. Esto es correcto para Ubuntu 24.04 y Debian 12.
¿Cómo configuro Fail2Ban con UFW como acción de baneo?
Si usa UFW como firewall, configure Fail2Ban para insertar reglas de baneo a través de UFW. Es el camino más sencillo, adecuado para la mayoría de configuraciones.
Cree un archivo de valores por defecto que establezca UFW como acción de baneo. El nombre zz-defaults.conf es intencional: en Ubuntu 24.04, el paquete incluye defaults-debian.conf que establece banaction = nftables. Su archivo debe ordenarse alfabéticamente después para sobreescribir ese valor.
sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = ufw
banaction_allports = ufw
backend = systemd
EOF
Reinicie y verifique:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Cuando Fail2Ban banea una IP, ejecuta ufw insert 1 deny from <IP> to any. Compruebe las reglas UFW después de un baneo:
sudo ufw status numbered
Verá las reglas deny de Fail2Ban en la parte superior de la lista.
¿Cómo configuro Fail2Ban para usar nftables en lugar de iptables?
Para servidores de producción que usan nftables directamente (sin UFW), utilice la acción de baneo nftables-multiport. Fail2Ban crea su propia tabla nftables y gestiona las reglas de baneo allí sin interferir con su conjunto de reglas existente.
Cree el archivo de valores por defecto. En Ubuntu 24.04, defaults-debian.conf ya establece banaction = nftables, así que este paso es técnicamente opcional. Pero es buena práctica ser explícito. En Debian 12, este archivo es obligatorio.
sudo tee /etc/fail2ban/jail.d/zz-defaults.conf > /dev/null << 'EOF'
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables[type=allports]
chain = input
backend = systemd
EOF
Reinicie y verifique:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Para confirmar la integración con nftables, liste la tabla de Fail2Ban:
sudo nft list tables
Debería ver una tabla llamada inet f2b-table. Después de un baneo, inspeccione su contenido:
sudo nft list table inet f2b-table
Comparación de acciones de baneo: UFW vs nftables
| Aspecto | UFW (banaction = ufw) |
nftables (banaction = nftables-multiport) |
|---|---|---|
| Comando de baneo | ufw insert 1 deny from <IP> |
Añade la IP a un conjunto nftables |
| Dónde aparecen las reglas | ufw status numbered |
nft list table inet f2b-table |
| Soporte IPv6 | Sí (UFW lo gestiona) | Sí (familia inet) |
| Persistencia | Las reglas UFW persisten entre reinicios | Fail2Ban las reaplica al iniciar |
| Rendimiento | Coincidencia lineal de reglas | Búsqueda basada en conjuntos (más rápida a escala) |
| Ideal para | Configuraciones simples, un solo servicio | Producción, muchas jails, alto volumen de baneos |
Elija un enfoque. No mezcle acciones de baneo UFW y nftables en el mismo servidor.
¿Cómo añado mi dirección IP a la lista blanca de Fail2Ban?
Añada su IP a ignoreip para evitar bloquearse a sí mismo. Esto es importante. Si escribe mal su contraseña tres veces, Fail2Ban baneará su propia IP. Perderá el acceso SSH.
Añada su IP a los valores por defecto:
sudo tee /etc/fail2ban/jail.d/01-whitelist.conf > /dev/null << 'EOF'
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE
EOF
Reemplace YOUR_IP_HERE por su dirección IP pública real. Puede encontrarla ejecutando curl -4 ifconfig.me desde su máquina local. Añada múltiples IP separadas por espacios.
Reinicie y verifique que la lista blanca está cargada:
sudo systemctl restart fail2ban
sudo fail2ban-client get sshd ignoreip
La salida lista todas las IP y rangos en la lista blanca. Confirme que su IP aparece en la lista.
Advertencia: Si se conecta desde una IP dinámica, añadirla a la lista blanca ofrece protección limitada. Mantenga un método de acceso secundario (acceso por consola desde el panel de su proveedor de hosting) como respaldo en caso de baneo.
¿Cómo protejo Nginx con jails Fail2Ban personalizadas?
Fail2Ban incluye varios filtros para Nginx. Los más útiles son nginx-http-auth para fuerza bruta en autenticación HTTP básica y nginx-botsearch para escáneres que sondean rutas inexistentes. También puede crear filtros personalizados para patrones específicos de su aplicación.
Jail nginx-http-auth
Esta jail banea las IP que fallan repetidamente en la autenticación HTTP básica. Lee del log de errores de Nginx.
sudo tee /etc/fail2ban/jail.d/nginx-http-auth.conf > /dev/null << 'EOF'
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
findtime = 600
bantime = 3600
EOF
Jail nginx-botsearch
Esta jail captura bots que escanean rutas vulnerables (/wp-admin, /phpmyadmin, /.env). Lee del log de acceso de Nginx las respuestas 404.
sudo tee /etc/fail2ban/jail.d/nginx-botsearch.conf > /dev/null << 'EOF'
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 7200
EOF
Filtro personalizado: banear errores 4xx excesivos
Para aplicaciones detrás de Nginx, puede querer banear IP que generen demasiados errores 4xx. Esto captura credential stuffing, abuso de API y enumeración de rutas. Los filtros integrados no cubren este caso, así que cree un filtro personalizado.
Cree el archivo de filtro:
sudo tee /etc/fail2ban/filter.d/nginx-4xx.conf > /dev/null << 'EOF'
[Definition]
failregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
ignoreregex = ^<HOST> - \S+ \[.*\] "[A-Z]+ /favicon\.ico
^<HOST> - \S+ \[.*\] "[A-Z]+ /robots\.txt
EOF
La failregex coincide con líneas del log de acceso de Nginx donde la respuesta es un código de estado 4xx. La ignoreregex excluye falsos positivos comunes como las peticiones a favicon.ico y robots.txt.
Cree la jail:
sudo tee /etc/fail2ban/jail.d/nginx-4xx.conf > /dev/null << 'EOF'
[nginx-4xx]
enabled = true
port = http,https
filter = nginx-4xx
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 600
bantime = 3600
EOF
El maxretry más alto de 20 evita banear usuarios legítimos que encuentran algunos 404 durante la navegación normal.
Reinicie Fail2Ban y compruebe que todas las jails están cargadas:
sudo systemctl restart fail2ban
sudo fail2ban-client status
Salida esperada mostrando todas las jails activas:
Status
|- Number of jail: 4
`- Jail list: nginx-4xx, nginx-botsearch, nginx-http-auth, sshd
Para más información sobre la protección de Nginx a nivel de aplicación, consulte la guía sobre rate limiting en Nginx.
¿Cómo pruebo los filtros de Fail2Ban con fail2ban-regex?
Antes de activar una jail, pruebe su filtro contra logs reales. La herramienta fail2ban-regex ejecuta un filtro contra un archivo de log e informa de las coincidencias. Esto evita desplegar un filtro que no coincida con nada (inútil) o que coincida con todo (banea usuarios legítimos).
Pruebe el filtro personalizado nginx-4xx:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Ejemplo de salida:
Running tests
=============
Use failregex filter file : nginx-4xx, basedir: /etc/fail2ban
Use log file : /var/log/nginx/access.log
Use encoding : utf-8
Results
=======
Failregex: 42 total
|- #) [# of hits] regular expression
| 1) [42] ^<HOST> - \S+ \[.*\] "[A-Z]+ .+" (400|401|403|404|405) \d+
`-
Ignoreregex: 3 total
Date template hits:
...
Lines: 1842 lines, 0 ignored, 42 matched, 1800 missed
Fíjese bien: la salida muestra 42 líneas coincidentes de 1842. Es una proporción razonable. Si el filtro coincidiera con el 90 % de las líneas, la regex es demasiado amplia. Si coincidiera con 0 líneas, o la regex es incorrecta o el log aún no tiene errores 4xx.
Para ver qué líneas coincidieron:
sudo fail2ban-regex --print-all-matched /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Para ver qué líneas no coincidieron (útil para ajustar):
sudo fail2ban-regex --print-all-missed /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-4xx.conf
Pruebe el filtro sshd integrado contra el journal de systemd:
sudo fail2ban-regex systemd-journal /etc/fail2ban/filter.d/sshd.conf
¿Cómo configuro la jail recidive para reincidentes?
La jail recidive vigila el propio log de Fail2Ban. Cuando una IP es baneada varias veces en cualquier jail, la jail recidive aplica un baneo más largo. Es una escalada: primera infracción = 1 hora, reincidentes = 1 semana.
En un servidor de producción con mucho tráfico, la jail recidive es lo que realmente mantiene alejados a los atacantes persistentes.
sudo tee /etc/fail2ban/jail.d/recidive.conf > /dev/null << 'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
banaction = %(banaction_allports)s
maxretry = 3
findtime = 86400
bantime = 604800
EOF
| Parámetro | Valor | Significado |
|---|---|---|
logpath |
/var/log/fail2ban.log |
Ruta de log de respaldo. Con backend = systemd, Fail2Ban lee sus propias entradas de journal en su lugar (el filtro recidive tiene una directiva journalmatch integrada) |
maxretry |
3 |
Se activa tras 3 baneos de otras jails |
findtime |
86400 |
Revisa las últimas 24 horas (86400 segundos) |
bantime |
604800 |
Banea durante 1 semana (604800 segundos) |
banaction |
%(banaction_allports)s |
Bloquea todos los puertos, no solo el que provocó el baneo |
El filtro recidive viene incluido con Fail2Ban en /etc/fail2ban/filter.d/recidive.conf. No necesita crearlo.
Reinicie y verifique:
sudo systemctl restart fail2ban
sudo fail2ban-client status recidive
¿Cómo monitorizo los baneos y desbaneo una dirección IP?
Fail2Ban proporciona fail2ban-client para todas las tareas de monitorización y gestión. Estos comandos funcionan independientemente de su backend de acción de baneo.
Comprobar el estado general
sudo fail2ban-client status
Lista todas las jails activas y sus contadores de baneo.
Comprobar una jail específica
sudo fail2ban-client status sshd
Muestra las IP actualmente baneadas, el total de baneos y los fallos actuales.
Banear manualmente una IP
sudo fail2ban-client set sshd banip 203.0.113.50
Desbanear una IP
sudo fail2ban-client set sshd unbanip 203.0.113.50
Si la IP fue baneada por la jail recidive, desbaneéla allí también:
sudo fail2ban-client set recidive unbanip 203.0.113.50
Comprobar qué acción de baneo usa una jail
sudo fail2ban-client get sshd actions
Recargar la configuración sin reiniciar
sudo fail2ban-client reload
Leer el log de Fail2Ban
journalctl -u fail2ban -f
Esto sigue el log del servicio Fail2Ban en tiempo real. Verá los eventos de baneo y desbaneo a medida que ocurran.
El log de aplicación de Fail2Ban con los detalles de los baneos:
sudo tail -f /var/log/fail2ban.log
Referencia de comandos fail2ban-client
| Comando | Función |
|---|---|
fail2ban-client status |
Listar todas las jails |
fail2ban-client status <jail> |
Mostrar detalles de la jail e IP baneadas |
fail2ban-client set <jail> banip <IP> |
Banear manualmente una IP |
fail2ban-client set <jail> unbanip <IP> |
Desbanear una IP |
fail2ban-client reload |
Recargar toda la configuración |
fail2ban-client reload <jail> |
Recargar una sola jail |
fail2ban-client get <jail> bantime |
Mostrar duración del baneo |
fail2ban-client get <jail> findtime |
Mostrar ventana de fallos |
fail2ban-client get <jail> maxretry |
Mostrar umbral de reintentos |
fail2ban-client get <jail> ignoreip |
Mostrar IP en lista blanca |
fail2ban-client get <jail> actions |
Mostrar acción de baneo en uso |
Verificación de extremo a extremo: provocar un baneo y confirmar que funciona
No asuma que su configuración funciona. Pruébela. Provoque un baneo real y verifique toda la cadena: detección en logs, acción de baneo, regla de firewall y desbaneo.
Paso 1: Desde otra máquina (no su IP en la lista blanca), intente inicios de sesión SSH con una contraseña incorrecta. Después de 3 fallos (coincidiendo con maxretry), la conexión debería ser rechazada.
Si no tiene una segunda máquina, use fail2ban-client para simular un baneo:
sudo fail2ban-client set sshd banip 198.51.100.25
Paso 2: Verifique que el baneo está registrado:
sudo fail2ban-client status sshd
La IP baneada debería aparecer en Banned IP list.
Paso 3: Verifique que la regla de firewall existe.
Para UFW:
sudo ufw status numbered | grep 198.51.100.25
Para nftables:
sudo nft list table inet f2b-table
La IP debería aparecer en un conjunto dentro de la tabla.
Paso 4: Desbanee y verifique la eliminación:
sudo fail2ban-client set sshd unbanip 198.51.100.25
sudo fail2ban-client status sshd
La IP ya no debería aparecer en la lista de baneos. Compruebe el firewall de nuevo para confirmar que la regla fue eliminada.
Referencia de parámetros de configuración de Fail2Ban
| Parámetro | Por defecto | Recomendado | Descripción |
|---|---|---|---|
bantime |
10m |
1h o 3600 |
Duración del baneo |
findtime |
10m |
10m o 600 |
Ventana para contar fallos |
maxretry |
5 |
3 para SSH, 5-20 para web |
Fallos antes del baneo |
ignoreip |
127.0.0.1/8 ::1 |
Añada su IP | IP que nunca se banean |
banaction |
nftables (Ubuntu 24.04), iptables-multiport (upstream) |
ufw o nftables-multiport |
Comando de firewall a ejecutar |
backend |
auto |
systemd |
Fuente de logs (journal systemd en distribuciones modernas) |
destemail |
root@localhost |
Su email | Destinatario de alertas |
action |
%(action_)s |
%(action_mwl)s para alertas por email |
Acción ejecutada al banear |
¿Algo salió mal?
Fail2Ban no arranca: Compruebe si hay errores de sintaxis en sus archivos de jail. Un corchete faltante o un valor inválido impedirán el arranque.
sudo fail2ban-client -t
Esto prueba la configuración sin iniciar el servicio. Corrija los errores que reporte.
La jail muestra 0 coincidencias pero hay ataques: El backend probablemente es incorrecto. En Ubuntu 24.04 y Debian 12, use backend = systemd. Si usa backend = auto y el sistema no tiene /var/log/auth.log, Fail2Ban no lee nada.
La IP baneada aún puede conectarse: La acción de baneo no coincide con su firewall. Si usa UFW, establezca banaction = ufw. Si usa nftables directamente, establezca banaction = nftables-multiport. Compruebe que la regla de firewall existe después de un baneo.
Se ha baneado a sí mismo: Acceda a su servidor a través de la consola web de su proveedor de hosting (VNC/KVM). Desde allí:
sudo fail2ban-client set sshd unbanip YOUR_IP
O detenga Fail2Ban por completo:
sudo systemctl stop fail2ban
Luego corrija su configuración ignoreip y reinicie.
Fail2Ban consume demasiada memoria: En servidores con archivos de log grandes, Fail2Ban puede consumir memoria. Establezca dbpurgeage para limitar el tamaño de la base de datos:
sudo tee /etc/fail2ban/jail.d/99-performance.conf > /dev/null << 'EOF'
[DEFAULT]
dbpurgeage = 7d
EOF
Copyright 2026 Virtua.Cloud. Todos los derechos reservados. Este contenido es una obra original del equipo de Virtua.Cloud. La reproducción, republicación o redistribución sin permiso escrito está prohibida.