Configurar Fail2ban¶
UFW bloquea tráfico no deseado, pero no detecta intentos de intrusión repetidos. Fail2ban vigila los logs del servidor y, cuando un IP acumula demasiados fallos de autenticación o peticiones a rutas sensibles, crea una regla temporal en UFW para bloquearla.
Cómo funciona¶
Fail2ban ejecuta ciclos periódicos de lectura sobre los logs que se le indican:
- Filtros — expresiones regulares que definen qué líneas del log son sospechosas (intentos de login fallidos, peticiones a
/wp-config.php, etc.). - Jaulas — combinan un filtro con una acción: si una IP supera
maxretryveces en el intervalo de tiempo definido, se aplica el baneo. - Acción
ufw— en vez de manipular iptables directamente, Fail2ban crea y elimina reglas de UFW, manteniendo todo integrado.
Protección activa con jaulas integradas en UFW.
Enfoque por niveles¶
Cada nivel añade una jaula al mismo fichero jail.local. Puedes parar en el que quieras — el nivel 1 es la base, el resto depende de los servicios que tengas.
| Nivel | Qué añade | ¿Aplicarlo? |
|---|---|---|
| 1 | Instalar + jaula SSH ([sshd]) | Obligatorio |
| 2 | Autenticación web (apache-auth / nginx-http-auth) | Solo si hay servidor web |
| 3 | Rutas sensibles (*-sensitive-paths) | Recomendado si hay web |
| 4 | Ajustes: ignoreip y baneo incremental | Opcional |
Traefik en Docker
Si tu servidor web corre detrás de Traefik en contenedores, fail2ban no lee los logs del host de forma directa — la parte de servidor web de esta guía no cubre ese caso. Necesitarás montar los logs del contenedor en el host o usar un plugin externo (por ejemplo f2b-traefik). La jaula sshd del Nivel 1 sí aplica igualmente.
Nivel 1 — Jaula SSH¶
Obligatorio. Es la base de la protección: los intentos de fuerza bruta sobre SSH se bloquean automáticamente tras maxretry fallos.
-
Comprobar si ya está instalado:
dpkg -l | grep fail2banrpm -qa | grep fail2ban -
Instalar si hace falta:
sudo apt install fail2bansudo dnf install fail2ban -
Comprobar que existe la acción
ufwde fail2ban:ls /etc/fail2ban/action.d/ufw.confSi no existe, usa
banaction = iptables-multiporten vez deufwen el paso siguiente. -
Crear
jail.localdesde cero (no copiarjail.conf— solo va aquí lo que sobreescribes):sudo vim /etc/fail2ban/jail.localContenido:
[DEFAULT] banaction = ufw [sshd] enabled = true port = 22 maxretry = 5 bantime = 3600Fail2ban trae el filtro
sshdde serie — no hace falta crearlo a mano.maxretry = 5ybantime = 3600son puntos de partida sensatos; se afinan en el Nivel 4. -
Reiniciar y comprobar el estado:
sudo service fail2ban restart sudo fail2ban-client status sudo fail2ban-client status sshd
Nivel 2 — Autenticación web¶
Solo si hay servidor web en la máquina (Apache o nginx). Bloquea los IPs que erran al autenticarse contra el panel o áreas restringidas.
-
Añadir al
jail.localya creado:[apache-auth] enabled = true[nginx-http-auth] enabled = trueFail2ban trae de serie los filtros
nginx-http-authynginx-botsearch(equivalentes aapache-auth/apache-badbots), así que no hace falta crearlos a mano. -
Aplicar y comprobar:
sudo service fail2ban restart sudo fail2ban-client status apache-auth sudo fail2ban-client status nginx-http-auth
Nivel 3 — Rutas sensibles¶
Recomendado si hay servidor web, con coste de mantenimiento bajo. Bloquea a quien hurga en ficheros que delatan un servidor fuera de control: wp-config.php, .env, .git/config, xmlrpc.php...
-
Crear el filtro para rutas sensibles:
sudo vim /etc/fail2ban/filter.d/apache-sensitive-paths.confContenido:
[Definition] failregex = ^<HOST> .* "(GET|POST) .*(wp-config\.php|\.env|\.git/config|xmlrpc\.php|\.htpasswd).*" (403|404) ignoreregex =sudo vim /etc/fail2ban/filter.d/nginx-sensitive-paths.confContenido (mismo patrón, adaptado al log de nginx):
[Definition] failregex = ^<HOST> .* "(GET|POST) .*(wp-config\.php|\.env|\.git/config|xmlrpc\.php|\.htpasswd).*" (403|404) ignoreregex = -
Añadir la jaula al
jail.local:[apache-sensitive-paths] enabled = true port = http,https filter = apache-sensitive-paths logpath = /var/log/apache2/*access.log maxretry = 1 bantime = 86400[nginx-sensitive-paths] enabled = true port = http,https filter = nginx-sensitive-paths logpath = /var/log/nginx/*access.log maxretry = 1 bantime = 86400 -
Aplicar y comprobar:
sudo service fail2ban restart sudo fail2ban-client status nginx-sensitive-paths
Nivel 4 — Ajustes¶
Opcional. Afina el comportamiento de todas las jaulas para tu estilo de administración.
-
Excluir tus propias IPs (no banearte a ti) en
[DEFAULT]dentro dejail.local:ignoreip = 127.0.0.1/8 <tu-ip-o-vpn>/<mascara>Si trabajas desde casa con IP dinámica, valora excluir tu VPN en vez de una IP concreta.
-
Endurecer el baneo ante reincidencia — el baneo crece con cada reincidencia de la misma IP (Fail2ban 0.11+):
bantime.increment = true bantime.factor = 2 bantime.maxtime = 86400 -
Ajustar la sensibilidad:
findtime(ventana de tiempo en la que cuentan los intentos) ymaxretry. Ejemplo en la jaulasshd:[sshd] maxretry = 5 findtime = 600Criterio: un servidor muy expuesto tolera menos intentos; un uso agresivo corta accesos legítimos con scripts que reintentan mucho.
-
Aplicar y comprobar el estado:
sudo service fail2ban restart sudo fail2ban-client status sudo ufw status numbered
Referencia¶
Estado de jail.local al completar los cuatro niveles (con servidor web nginx):
[DEFAULT]
banaction = ufw
ignoreip = 127.0.0.1/8 <tu-ip-o-vpn>/<mascara>
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 86400
[sshd]
enabled = true
port = 22
maxretry = 5
bantime = 3600
findtime = 600
[nginx-http-auth]
enabled = true
[nginx-sensitive-paths]
enabled = true
port = http,https
filter = nginx-sensitive-paths
logpath = /var/log/nginx/*access.log
maxretry = 1
bantime = 86400
Si usas Apache, sustituye la jaula web por [apache-auth] y [apache-sensitive-paths] (con logpath = /var/log/apache2/*access.log), y recuerda el filtro creado en el Nivel 3.
Verificar¶
-
Estado general y de cada jaula:
sudo fail2ban-client status sudo fail2ban-client status sshd sudo ufw status numbered
Para una prueba en vivo sin esperar a un atacante real, fuerza maxretry fallos de login contra una IP de prueba y confirma que la regla aparece en ufw status numbered con la IP bloqueada.
Y ahora qué
Fail2ban está activo y bloqueando intentos sospechosos. El siguiente paso es configurar las Actualizaciones automáticas para mantener el sistema parcheado.