Uno de los retos más interesantes al desarrollar un panel de hosting propio es la seguridad real en producción. No la teórica, sino la que funciona cuando hay tráfico, bots y ataques constantes.
En este artículo explico cómo hemos pasado de no poder proteger WordPress a nivel servidor a tener un sistema automático, centralizado y sin dependencias del CMS, utilizando Fail2Ban junto con Caddy y PHP-FPM.
El problema inicial
El objetivo era claro: bloquear ataques de fuerza bruta contra wp-login.php y xmlrpc.php sin instalar plugins en WordPress.
Fail2Ban necesita algo básico para funcionar:
- Logs con peticiones HTTP
- IP del cliente
- Rutas accedidas
Pero en nuestro sistema había un problema crítico:
Caddy no estaba generando access logs para los hostings.
Esto implicaba que:
- No había registro de accesos
- No había forma de detectar ataques
- Fail2Ban no podía actuar
No era un problema de configuración de seguridad, sino de falta de datos.
Por qué ocurría
Nuestro stack funciona así:
- Caddy gestiona las peticiones HTTP
- PHP se ejecuta mediante PHP-FPM
- Los vhosts se generan automáticamente desde el panel
El error estaba en el sistema de provisioning:
- Solo algunos dominios tenían logging activado
- La mayoría de hostings no generaban ningún log
Esto hacía imposible proteger rutas como /wp-login.php, porque simplemente no existía información sobre los accesos.
La solución: logging centralizado
La solución no estaba en Fail2Ban, sino en el servidor web.
Se implementó un sistema para que todos los hostings escriban logs de acceso de forma automática en un único archivo:
Resultado en producción:
- 21 hostings activos registrados
- 42 dominios (incluyendo www)
- Todas las peticiones HTTP registradas
Ahora cada acceso a cualquier sitio pasa por ese log, incluyendo:
/wp-login.php/xmlrpc.php
Automatización desde el panel
Este cambio no es manual.
Se ha integrado en el sistema de creación de hostings:
- Cada vez que se crea un nuevo sitio
- Se genera su configuración en Caddy
- Se activa automáticamente el logging
Esto se ejecuta internamente en el flujo:
El resultado es que todos los hostings nuevos ya incluyen logging sin intervención adicional.
Configuración de Fail2Ban
Una vez disponibles los logs, Fail2Ban puede trabajar correctamente.
Actualmente hay cuatro jails activos:
Seguridad base
- sshd: protege accesos SSH
Panel interno
- musedock-panel: protege login de administración (puerto 8444)
- musedock-portal: protege acceso de clientes (puerto 8446)
WordPress
- musedock-wordpress: protege
/wp-login.phpy/xmlrpc.phpen todos los hostings
Este último es el más relevante porque aplica a todos los sitios simultáneamente.
Cómo funciona el sistema
El flujo completo es el siguiente:
- Un atacante intenta acceder a WordPress
- Realiza múltiples peticiones POST a
/wp-login.php - Caddy registra cada petición en el log
- Fail2Ban analiza el log en tiempo real
- Si detecta 10 intentos en 5 minutos:
- Banea la IP
- Bloquea acceso en puertos 80 y 443
- Durante 1 hora
Todo esto ocurre sin instalar ningún plugin en WordPress.
Verificación en tiempo real
Para comprobar que el sistema funciona:
Al hacer un intento de login en cualquier WordPress:
- La petición aparece en el log inmediatamente
- Fail2Ban puede procesarla
Gestión desde el panel
Además de la protección automática, se ha construido una interfaz para gestionar Fail2Ban sin usar consola.
Funcionalidades añadidas
- Estado del servicio (activo, uptime, jails)
- Número total de IPs baneadas
- Listado de IPs bloqueadas por jail
Acciones disponibles
- Banear IP manualmente
- Desbanear IP
- Añadir IP a whitelist
Whitelist (ignoreip)
El sistema permite gestionar IPs que nunca deben ser bloqueadas.
Esto se guarda en:
Características:
- Soporte para IPs individuales y rangos CIDR
- Mantiene siempre:
- 127.0.0.1/8
- ::1
- Recarga automática de Fail2Ban tras cambios
Esto evita problemas típicos como bloquearse a uno mismo durante pruebas.
UX y operativa
Se han añadido confirmaciones visuales en acciones críticas:
- Banear IP
- Desbanear IP
- Añadir a whitelist
El objetivo es evitar errores y hacer el sistema usable sin necesidad de conocimientos avanzados.
Qué hemos aprendido
Este desarrollo deja varias conclusiones importantes:
- Fail2Ban depende completamente de los logs
- Si el servidor web no registra accesos, no hay seguridad posible
- El problema no siempre está donde parece (no era Fail2Ban, era Caddy)
- La automatización en el provisioning es clave para escalar
Conclusión
Ahora el sistema:
- Protege todos los WordPress automáticamente
- No depende de plugins
- Funciona a nivel servidor
- Escala con cada nuevo hosting
Y lo más importante:
La seguridad ya no depende del usuario final ni de la configuración de cada instalación.
Es parte de la infraestructura.