Por qué autoalojar Fail2ban en un VPS
Fail2ban es una de las herramientas de protección más sencillas y extendidas para un servidor expuesto: lee de forma continua sus logs, aplica expresiones regulares (los filtros) para detectar los intentos de intrusión y bloquea la IP culpable añadiéndola a nftables o iptables durante un tiempo configurable. En un VPS es una primera línea de defensa que conviene instalar antes que el resto, porque no depende de ningún servicio externo, consume poco y protege SSH contra la fuerza bruta desde que se activa el jail. Más allá de SSH, puede extenderlo a Nginx (intentos de autenticación, escaneos de URL), Postfix, WordPress o cualquier servicio que escriba logs. Todo funciona en local en su máquina: no sale ningún dato, no interviene ningún servicio de terceros. Es una solución autónoma y fácil de auditar, siempre que la revise de vez en cuando, como veremos más abajo.
Los beneficios concretos de esta plantilla
- Bloqueo automático — las IP que fuerzan SSH se bloquean en cuanto se alcanza el umbral
maxretrydentro de la ventanafindtime. - Filtros para numerosos servicios — SSH, Nginx, Apache, Postfix, WordPress, y filtros personalizados escritos en
filter.d. - Huella mínima — funciona sin problema en el más pequeño de los VPS.
- Bloqueo progresivo (reincidencia) — cuanto más reincide una IP, más largo es el bloqueo.
- Notificaciones por correo electrónico — posibles en cada bloqueo, con las acciones
action_mwoaction_mwldejail.conf. - Autónomo y local — ninguna dependencia de red en el día a día, fácil de auditar y de versionar.
Requisitos cifrados para alojarlo
Fail2ban es frugal: un VPS de 1 vCPU y 512 MB de RAM basta para ejecutarlo, sin impacto perceptible (recomendación editorial, que debe medirse con su propia carga). En cuanto al software, el README original de la versión 1.1.1 pide Python 3.5 o superior. Dos componentes son opcionales: pyinotify 0.8.3 o superior para vigilar archivos (kernel Linux 2.6.13 o superior), y systemd 204 o superior con el paquete python-systemd para leer el journal. Fail2ban se instala directamente en el sistema (no hace falta Docker) y exige acceso root, un backend de firewall (nftables o iptables) y acceso a los logs de los servicios a proteger: el journal de systemd o /var/log/auth.log para SSH según la distribución, y los logs access y error de Nginx. Guarda su estado en una base SQLite, /var/lib/fail2ban/fail2ban.sqlite3 por defecto. No se necesita ningún dominio ni puerto adicional. La regla de oro: rellene ignoreip con su IP antes de activar el bloqueo, para no dejarse fuera de su propio servidor.
Instalar y configurar Fail2ban en su VPS
Instalar Fail2ban
En Debian o Ubuntu:
sudo apt update && sudo apt install fail2ban. El servicio arranca automáticamente. Compruébelo consudo systemctl status fail2ban.Crear un jail.local
No modifique nunca
jail.confdirectamente. Escriba sus ajustes en/etc/fail2ban/jail.local, que los sobrescribe: ahí es donde se definenbantime,findtime,maxretryy sobre todoignoreip = 127.0.0.1/8 ::1 SU_IPpara protegerse de un autobloqueo. Los valores por defecto dejail.confsonbantime = 10m,findtime = 10mymaxretry = 5.Activar la protección SSH
Todos los jails están desactivados por defecto en
jail.conf: active explícitamente[sshd]enjail.localconenabled = true, por ejemplomaxretry = 3ybantime = 1h. Tras 3 fallos dentro de la ventanafindtime, la IP queda bloqueada una hora a nivel de firewall.Añadir un jail para Nginx
Active los jails
[nginx-http-auth]y[nginx-botsearch], que incluyejail.conf, y compruebe quelogpathapunta a sus logs de Nginx. Esto bloquea los intentos de autenticación repetidos y los escaneos de URL maliciosos.Probar la configuración y recargarla
Compruebe primero la sintaxis:
sudo fail2ban-client -t. Después aplíquela:sudo fail2ban-client reload(osudo systemctl restart fail2ban).sudo fail2ban-client statuslista los jails activos ysudo fail2ban-client status sshdmuestra las IP bloqueadas en ese momento.Probar un bloqueo y el desbloqueo
Compruebe el filtro con su propio journal mediante
sudo fail2ban-regex systemd-journal sshd. Para simular un bloqueo sin atacar a nadie:sudo fail2ban-client set sshd banip 203.0.113.10, y lea despuéssudo fail2ban-client status sshd. Para liberar una IP legítima bloqueada por error:sudo fail2ban-client set sshd unbanip X.X.X.X.Conectarse por primera vez
No hay ninguna interfaz web ni cuenta que crear: fail2ban es un demonio del sistema que, con el ajuste de la plantilla, bloquea las IP tras 4 fallos SSH en 10 minutos. Por SSH:
fail2ban-client status sshd(IP bloqueadas),fail2ban-client set sshd unbanip <IP>(desbloquear). Ajuste estos umbrales enjail.local.
ignoreip, duración del bloqueo y reincidencia
ignoreip acepta direcciones IP, máscaras CIDR o nombres de host DNS, separados por espacios o comas. Por defecto ignoreself = true: las direcciones locales del propio servidor nunca se bloquean, pero su IP de oficina o de casa no queda cubierta por eso. Si cambia a menudo, declare un nombre de host dinámico o use ignorecommand, un comando externo que recibe la IP y responde si debe ignorarse. Mantenga también un acceso de emergencia que no dependa de SSH, como la consola de su proveedor de VPS: un autobloqueo se resuelve entonces sin ayuda externa. La duración se fija con bantime, en segundos o con los sufijos m, h, d, w, mo e y. Actúa como duración inicial cuando el bloqueo progresivo está activado. Para los reincidentes, jail.conf incluye además un jail recidive, que lee el propio log de fail2ban.
Bloqueo progresivo: fórmula, tope y memoria
Active el bloqueo progresivo en jail.local con bantime.increment = true. La fórmula por defecto multiplica bantime por 1, 2, 4, 8, 16 y así sucesivamente en cada reincidencia; bantime.factor (1 por defecto) es un multiplicador común, y bantime.maxtime limita la duración en segundos, por ejemplo bantime.maxtime = 604800 para siete días. Hay un punto que suele pasarse por alto: fail2ban encuentra los bloqueos anteriores en su base de datos, que se purga según dbpurgeage (un día por defecto en fail2ban.conf). Para que se encuentren reincidencias muy espaciadas, auméntelo; el comentario del jail recidive en jail.conf cita 648000 segundos. Combine todo con la desactivación de la autenticación por contraseña (solo claves SSH): Fail2ban se convierte entonces en una red de seguridad y no en su única muralla.
Elegir el backend: auto, pyinotify, polling o systemd
El backend es la forma en que un jail lee sus logs. El valor por defecto de jail.conf es backend = auto, que cada jail puede sobrescribir. En Debian y Ubuntu, el archivo paths-debian.conf del paquete original 1.1.1 fija sshd_backend = systemd: sshd se lee entonces del journal de systemd, no de /var/log/auth.log. Lea sudo fail2ban-client status sshd para saber qué se vigila realmente: la línea File list indica archivos, la línea Journal matches indica el journal. Una distribución puede cambiar estos valores, así que no dé nada por supuesto: compruébelo. Cambiar de backend se hace jail por jail, en jail.local, seguido de sudo fail2ban-client reload.
Los cuatro backends de Fail2ban
Desplace la tabla
| Backend | Qué vigila | A tener en cuenta |
|---|---|---|
| auto | Archivos (pyinotify y luego polling); pasa a systemd si no existe ningún archivo de `logpath` y el filtro define `journalmatch` | Valor por defecto de `jail.conf` |
| pyinotify | Archivos, mediante los eventos inotify del kernel | Solo Linux, requiere el módulo Python pyinotify; según la documentación, más adecuado para archivos que polling |
| polling | Archivos, releyéndolos a intervalos regulares | Sin biblioteca externa, el recurso más sencillo |
| systemd | El journal de systemd, mediante python-systemd | `logpath` no es válido; el filtro usa `journalmatch`; ajustes `journalflags` y `rotated` |
Comprobar que el jail sigue vigilando
Un jail iniciado no es necesariamente un jail que lee. Caso comunicado, no confirmado por los mantenedores: en la incidencia 4250 de fail2ban, abierta en octubre 2026, un administrador con Debian y fail2ban 1.1.1 describe un jail sshd con backend systemd que deja de bloquear entre uno y dos días después del arranque, mientras sus jails de Nginx y Postfix siguen funcionando. Otros dos administradores, ambos con FreeBSD según sus mensajes, comunican un síntoma parecido con el backend pyinotify; uno dice que todo se estabilizó al pasar a polling. Un mantenedor señaló que la incidencia original trataba del backend systemd y que quizá los dos síntomas no estén relacionados. Un último participante, con Arch y el backend systemd, describe la misma parada tras una rotación del journal y plantea una hipótesis sobre el ajuste rotated: sigue sin confirmarse. La causa no está establecida a día de hoy, y nada permite generalizar a su servidor. La comprobación, en cambio, lleva un minuto.
Comprobar en cuatro pasos que el jail sigue leyendo
Leer el estado del jail
sudo fail2ban-client status sshdmuestraCurrently failedyTotal failedpara el filtro,File listoJournal matchespara la fuente, y despuésCurrently banned,Total bannedyBanned IP listpara la acción. AnoteTotal failed.Comparar con el log
Cuente los fallos reales en el mismo periodo:
sudo journalctl _COMM=sshd --since "1 hour ago" | grep -c "Failed password", osudo grep -c "Failed password" /var/log/auth.logsi el jail lee ese archivo. Vuelva a leerTotal failed: debería haber aumentado. Compare la tendencia, no la igualdad exacta, porque las IP deignoreipno cuentan.Leer el log de fail2ban
sudo tail -n 50 /var/log/fail2ban.log: un jail sano escribe líneasFoundseguidas deBan. Varios días de líneasUnbansolas, mientras el log de autenticación muestra intentos, delatan un jail ciego.Reiniciar y cambiar de backend si hace falta
sudo systemctl restart fail2banreanuda la lectura; la incidencia describe un funcionamiento normal durante uno o dos días tras cada arranque. Para un jail de archivos,backend = pollinges el recurso más sencillo. Programe esta comprobación (cron o una herramienta de supervisión) en lugar de confiar en la ausencia de alertas.
Resolución de problemas: los mensajes de error reales
Estos mensajes proceden del código fuente de Fail2ban 1.1.1 (clientes y lectores de configuración); el nivel de registro por defecto es INFO. En cada caso el comando de partida es el mismo: sudo fail2ban-client -t prueba la configuración, sudo journalctl -u fail2ban da el principio de la historia.
Mensajes de error habituales y remedios
Have not found any log file for 'sshd' jail.— ellogpathdel jail no apunta a ningún archivo existente y el arranque falla, salvo conskip_if_nologs = true. Con el backendauto, un jail cuyo filtro definejournalmatchpasa a systemd. Corrija la ruta o fijebackend = systemd.No file(s) found for glob /var/log/nginx/error.log— un patrón delogpathno coincide con nada. Compruebe la ubicación real de los logs de Nginx conls /var/log/nginx.Unable to read the filter 'nginx-xyz'— el nombre dado afilter =no existe enfilter.d. Corrija la errata o añada su archivo de filtro.Failed to access socket path: /var/run/fail2ban/fail2ban.sock. Is fail2ban running?— el cliente no encuentra el socket del servidor. El servicio está detenido o falla:sudo systemctl status fail2bany después su log.Permission denied to socket: ... (you must be root)— el comandofail2ban-clientse lanzó sin los derechos suficientes. Vuelva a lanzarlo consudo.Unable to contact server. Is it running?— el socket existe pero el servidor no responde. Reinicie el servicio y lea su log de arranque.[sshd] Journal reader seems to be offline, reopen journal— fail2ban detectó que su lectura del journal de systemd se había interrumpido (rotación) y lo reabre. Este mensaje es de nivelMSG, por debajo deINFO: su ausencia en un log normal no prueba nada, de ahí la comprobación de la sección anterior.Error reading line from systemd journal— error de lectura del journal de systemd, seguido de la causa del sistema. Compruebe los permisos del servicio y el estado del journal conjournalctl --verify.
nftables o iptables, firewall del VPS y copia de seguridad
La acción de bloqueo se elige con banaction. jail.conf propone iptables-multiport como ejemplo comentado; el archivo paths-debian.conf del paquete 1.1.1 fija banaction = nftables y banaction_allports = nftables[type=allports]. La acción nftables crea por defecto la tabla f2b-table (familia inet) y la cadena f2b-chain, enganchada a la entrada con prioridad -1; sudo nft list table inet f2b-table muestra las IP bloqueadas. Elija una sola familia de acciones, la misma que el resto de su firewall, o buscará sus reglas en la tabla equivocada. El firewall del VPS actúa antes: filtra lo que llega a la máquina, por ejemplo limitando SSH a sus direcciones, mientras que Fail2ban reacciona a lo que cuentan los logs. Se complementan, pero mantenga ignoreip coherente con sus reglas. Detrás de un proxy o de una CDN, los logs muestran la IP del proxy: restituya la IP real antes de bloquear, o bloqueará el proxy. Para la copia de seguridad, archive la configuración (sudo tar czf fail2ban-config.tar.gz /etc/fail2ban) y la salida de sudo fail2ban-client --dp, que documenta la configuración efectiva. La base /var/lib/fail2ban/fail2ban.sqlite3 conserva la memoria de los bloqueos.
La documentación oficial
Para la configuración avanzada, las opciones propias de la herramienta y los cambios de versión, consulte la documentación oficial de Fail2Ban. Esta guía cubre la puesta en línea en un VPS ServOrbit; la documentación del editor sigue siendo la referencia para los ajustes finos.