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:

  1. Monitoreo de logs — El daemon logtarget de Fail2Ban vigila archivos de log (por ejemplo, /var/log/auth.log, /var/log/nginx/error.log) usando inotify o sondeo.
  2. 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.
  3. Verificación de umbral — Una vez que el contador alcanza maxretry dentro de la ventana findtime, la IP se considera hostil.
  4. 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 bantime segundos.

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ámetroValorSignificado
maxretry4Intentos fallidos antes del baneo
findtime1hVentana para contar fallos
bantime24hTiempo que permanece baneada la IP
ignoreipLista CIDRIPs que nunca se banean
backendsystemdLeer logs de journald

Advertencia: Siempre añade tu propia IP o subred de gestión a ignoreip antes 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

HerramientaMecanismoLenguajeAlcanceComunidad
Fail2BanRegex de logs + firewall localPythonServidor localNo
CrowdSecAnálisis conductual + listas compartidasGoMulti-servidor
DenyHostsSolo /etc/hosts.deny SSHPythonSolo SSHOpcional
SSHGuardDaemon C, multi-backendCServicios limitadosNo

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 bantime en al menos 24h para SSH — los baneos de 10 minutos apenas ralentizan a atacantes determinados
  • Monitorea el log de Fail2Ban en /var/log/fail2ban.log con un agregador de logs
  • Haz copia de seguridad de /var/lib/fail2ban/fail2ban.sqlite3 para 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 ignoreip perió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 — usa jail.local o archivos drop-in en jail.d/
  • Siempre configura ignoreip con tu propia IP antes de habilitar jails estrictos
  • El baneo progresivo (bantime.increment) hace que los atacantes persistentes sean efectivamente permanentes
  • Usa fail2ban-regex para probar y validar patrones de filtros antes del despliegue

Artículos Relacionados