TL;DR — Resumen Rápido
Fail2Ban guía completa: instalación, jails SSH, baneo progresivo, filtros personalizados, protección Nginx/Apache/correo e integración con Cloudflare en Linux.
Cada servidor Linux expuesto a internet está bajo ataque constante. Los bots automatizados escanean todo el espacio de direcciones IPv4 en horas, probando miles de combinaciones de usuario y contraseña contra SSH y otros servicios. Fail2Ban es un framework de prevención de intrusiones basado en logs que detecta estos ataques en tiempo real e instruye al firewall a bloquear las IPs ofensoras, automáticamente y sin intervención manual. Esta guía cubre la configuración completa de Fail2Ban: instalación, configuración de jails SSH, baneo progresivo, creación de filtros personalizados, protección para Nginx, Apache y servidores de correo, e integración con la API de Cloudflare.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Un servidor Linux con Ubuntu 20.04/22.04/24.04, Debian 11/12 o RHEL/Rocky/AlmaLinux 8/9
- Acceso root o sudo
- Acceso SSH al servidor
- iptables, nftables o firewalld gestionando tu firewall
- Familiaridad básica con la gestión de servicios systemd
Cómo Funciona Fail2Ban
Fail2Ban opera en un bucle monitorear → coincidir → banear:
- Monitoreo de logs — El daemon
logtargetde Fail2Ban vigila archivos de log (por ejemplo,/var/log/auth.log,/var/log/nginx/error.log) usando inotify o sondeo. - Coincidencia de regex — Cada jail hace referencia a un filtro que contiene uno o más patrones
failregex. Cuando una línea de log coincide, Fail2Ban incrementa un contador de fallos para la IP de origen. - Verificación de umbral — Una vez que el contador alcanza
maxretrydentro de la ventanafindtime, la IP se considera hostil. - Baneo en el firewall — Fail2Ban llama a una acción (típicamente iptables, nftables o firewalld) para insertar una regla DROP para la IP ofensora. La regla se elimina automáticamente después de
bantimesegundos.
Los jails se definen en archivos de configuración y combinan un filtro (qué coincidir) con una acción (qué hacer). El servicio almacena su estado en /var/lib/fail2ban/, por lo que los baneos sobreviven a un reinicio del servicio.
Instalación
Ubuntu / Debian
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
RHEL / Rocky / AlmaLinux
Se requiere el repositorio EPEL:
sudo dnf install epel-release -y
sudo dnf install fail2ban -y
sudo systemctl enable --now fail2ban
En sistemas de la familia RHEL, firewalld es el backend predeterminado. Instala la integración opcional:
sudo dnf install fail2ban-firewalld -y
Verifica que Fail2Ban esté en ejecución:
sudo fail2ban-client status
Configuración del Jail SSH
Nunca edites /etc/fail2ban/jail.conf directamente — se sobreescribe con actualizaciones de paquetes. En su lugar, crea tus sobrescrituras en /etc/fail2ban/jail.local:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
O usa el enfoque drop-in recomendado:
sudo nano /etc/fail2ban/jail.d/sshd.local
Un jail SSH completo y listo para producción:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
backend = systemd
maxretry = 4
findtime = 1h
bantime = 24h
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
Parámetros clave explicados:
| Parámetro | Valor | Significado |
|---|---|---|
maxretry | 4 | Intentos fallidos antes del baneo |
findtime | 1h | Ventana para contar fallos |
bantime | 24h | Tiempo que permanece baneada la IP |
ignoreip | Lista CIDR | IPs que nunca se banean |
backend | systemd | Leer logs de journald |
Advertencia: Siempre añade tu propia IP o subred de gestión a
ignoreipantes de habilitar jails estrictos. Bloquearte en una VM en la nube requiere acceso por consola para recuperarte.
Después de cualquier cambio de configuración, recarga Fail2Ban:
sudo fail2ban-client reload
Baneo Progresivo
Los baneos estándar liberan al atacante después de que expire bantime. El baneo progresivo aumenta exponencialmente la duración del baneo para los reincidentes, haciendo que los atacantes persistentes sean efectivamente permanentes.
Añade estos ajustes a [DEFAULT] en jail.local:
[DEFAULT]
bantime.increment = true
bantime.factor = 1
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
bantime.multipliers = 1 5 30 60 300 720 1440 2880
bantime.maxtime = 5w
bantime.overalljails = true
Con la secuencia de multiplicadores 1 5 30 60 300 720 1440 2880 y un bantime base de 10 minutos:
- 1er baneo: 10 minutos
- 2do baneo: 50 minutos
- 3er baneo: 5 horas
- 4to baneo: 10 horas
- 5to baneo: ~2 días
- …hasta un máximo de 5 semanas
bantime.overalljails = true cuenta los fallos en todos los jails, por lo que una IP que activa tanto el jail SSH como el de Nginx acumula baneos más rápido.
Creación de Filtros Personalizados
Cuando ejecutas una aplicación no estándar, necesitas un filtro personalizado. Los filtros viven en /etc/fail2ban/filter.d/.
Ejemplo: proteger una API Node.js Express que registra:
2026-03-22 14:05:33 [AUTH FAIL] 203.0.113.42 - Invalid token on /api/v1/login
Crea /etc/fail2ban/filter.d/myapp-auth.conf:
[Definition]
failregex = ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} \[AUTH FAIL\] <HOST> -
ignoreregex =
<HOST> es el token mágico de Fail2Ban que captura la dirección IPv4 o IPv6.
Prueba tu regex contra el archivo de log antes de activarlo:
sudo fail2ban-regex /var/log/myapp/app.log /etc/fail2ban/filter.d/myapp-auth.conf
Protección de Nginx
Fail2Ban incluye varios filtros para Nginx. Actívalos añadiendo a jail.local o un drop-in:
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 1h
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 24h
findtime = 1h
[nginx-limit-req]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 10m
nginx-http-auth captura intentos fallidos de Autenticación Básica. nginx-botsearch bloquea IPs que escanean en busca de WordPress, phpMyAdmin y endpoints similares. nginx-limit-req banea IPs que activan tu límite de velocidad limit_req_zone.
Jails para Apache y Servidor de Correo
Apache
[apache-auth]
enabled = true
port = http,https
logpath = /var/log/apache2/error.log
maxretry = 3
[apache-badbots]
enabled = true
port = http,https
logpath = /var/log/apache2/access.log
bantime = 48h
Postfix / Dovecot (Servidor de Correo)
[postfix]
enabled = true
port = smtp,465,submission
logpath = /var/log/mail.log
maxretry = 3
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps,submission,465,sieve
logpath = /var/log/mail.log
maxretry = 3
bantime = 12h
Gestión de Baneos con fail2ban-client
# Mostrar todos los jails activos
sudo fail2ban-client status
# Mostrar IPs baneadas en un jail específico
sudo fail2ban-client status sshd
# Banear manualmente una IP
sudo fail2ban-client set sshd banip 203.0.113.42
# Desbanear una IP
sudo fail2ban-client set sshd unbanip 203.0.113.42
# Recargar configuración sin reiniciar
sudo fail2ban-client reload
# Ver todas las IPs baneadas en todos los jails
sudo fail2ban-client banned
Configuración de Acciones
Las acciones definen cómo Fail2Ban banea una IP. Configura la acción predeterminada en [DEFAULT]:
[DEFAULT]
# iptables (clásico, más compatible)
banaction = iptables-multiport
# nftables (recomendado para distribuciones modernas)
banaction = nftables-multiport
# firewalld (RHEL/Rocky)
banaction = firewallcmd-ipset
# Enviar notificación por email al banear
action = %(action_mwl)s
Prueba de Filtros con fail2ban-regex
# Probar contra un archivo de log
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
# Probar con una línea de log específica
sudo fail2ban-regex "Mar 22 14:05:33 server sshd[12345]: Failed password for root from 203.0.113.42 port 54321 ssh2" sshd
Integración con Cloudflare
Si tu servidor está detrás de Cloudflare, las IPs en tus logs son IPs de proxy de Cloudflare. Solución:
Opción 1 — Restaurar IPs reales via el encabezado CF-Connecting-IP. Configura Nginx para usarlo:
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;
Opción 2 — Banear en el borde de Cloudflare usando la acción cloudflare:
[DEFAULT]
cftoken = TU_TOKEN_API_CLOUDFLARE
cfzoneid = TU_ZONE_ID
[nginx-botsearch]
enabled = true
action = %(action_)s
cloudflare[cftoken="%(cftoken)s", cfzoneid="%(cfzoneid)s"]
Comparativa: Fail2Ban vs Alternativas
| Herramienta | Mecanismo | Lenguaje | Alcance | Comunidad |
|---|---|---|---|---|
| Fail2Ban | Regex de logs + firewall local | Python | Servidor local | No |
| CrowdSec | Análisis conductual + listas compartidas | Go | Multi-servidor | Sí |
| DenyHosts | Solo /etc/hosts.deny SSH | Python | Solo SSH | Opcional |
| SSHGuard | Daemon C, multi-backend | C | Servicios limitados | No |
Consejos de Endurecimiento en Producción
- Cambia el puerto SSH del 22 a uno no estándar para reducir el ruido de escaneo automático
- Establece
bantimeen al menos 24h para SSH — los baneos de 10 minutos apenas ralentizan a atacantes determinados - Monitorea el log de Fail2Ban en
/var/log/fail2ban.logcon un agregador de logs - Haz copia de seguridad de
/var/lib/fail2ban/fail2ban.sqlite3para preservar el historial de baneos - Combina con la limitación de velocidad de UFW (
sudo ufw limit ssh) para defensa en profundidad - Audita tu lista
ignoreipperiódicamente para eliminar IPs antiguas olvidadas
Resumen
Fail2Ban proporciona protección robusta y automatizada contra fuerza bruta para cualquier servidor Linux que exponga servicios a internet. Puntos clave:
- Fail2Ban monitorea logs, hace coincidir patrones de fallos con regex y añade reglas de firewall para bloquear IPs ofensoras
- Nunca edites
jail.conf— usajail.localo archivos drop-in enjail.d/ - Siempre configura
ignoreipcon tu propia IP antes de habilitar jails estrictos - El baneo progresivo (
bantime.increment) hace que los atacantes persistentes sean efectivamente permanentes - Usa
fail2ban-regexpara probar y validar patrones de filtros antes del despliegue