Cómo instalar CrowdSec como WAF comunitario
Índice de contenidos
- Puntos clave
- Por qué vale la pena el cambio desde fail2ban
- Instalación del agente
- Collections: trabajo ahorrado desde el primer día
- Decirle al agente qué logs leer
- Diagnóstico: qué ver los primeros días
- Los bouncers: de detección a bloqueo efectivo
- Activar el WAF: componente AppSec y virtual patching
- Remediación con captcha: no todo es ban
- El valor real de la blocklist comunitaria
- Monitorización
- Whitelists y errores comunes
- Cuándo no compensa CrowdSec
- Mi recomendación
- Preguntas frecuentes
- ¿Cómo saber si CrowdSec está bloqueando tráfico de verdad?
- ¿Necesito Traefik para usar CrowdSec?
- ¿La blocklist comunitaria de CrowdSec es gratis?
- Fuentes
Probado con CrowdSec 1.8.1 · firewall bouncer 0.0.36 · Traefik 3.7 · Debian 13.6 · verificado
Actualizado: 2026-09-16
CrowdSec 1.8.1 sustituye a fail2ban separando la detección (agente + LAPI) del bloqueo (bouncers). Instala el agente con el script oficial en Debian o Ubuntu y revisa la acquisition que genera el instalador. Después añade el bouncer de Traefik o del firewall, el WAF AppSec con sus dos collections y, si quieres, el captcha de Cloudflare Turnstile.
CrowdSec, la evolución moderna de fail2ban, se instala en Debian o Ubuntu con el script oficial (curl -s https://install.crowdsec.net | sudo sh y luego sudo apt install crowdsec). La versión estable es la 1.8.1, del 3 de septiembre de 2026. Después activas las collections adecuadas y añades al menos un bouncer, el componente que consulta las decisiones de bloqueo y las aplica, por ejemplo en Traefik o en el firewall. Ese bouncer es lo que lleva de la detección a la protección real.
CrowdSec[1] es un WAF comunitario, es decir, un cortafuegos de aplicación web: la capa que filtra peticiones HTTP maliciosas antes de que lleguen a tu aplicación. Separa la detección del bloqueo, inspecciona cada petición con su componente AppSec y se apoya en una blocklist alimentada por las instalaciones que comparten sus detecciones. Esta guía recorre la instalación, la integración con Traefik y el WAF explicando por qué existe cada pieza.
Actualicé la guía el 16 de septiembre de 2026 y repetí sus pasos en una máquina arm64. Probé el paquete en un contenedor Debian 13.6 con systemd y el plugin 1.7.1 sobre Traefik 3.7.13. Otras pruebas (el fallo de arranque de AppSec, force_inotify, la latencia y la resolución del captcha) corrieron en una pila Docker con la imagen crowdsecurity/crowdsec:v1.8.1. Las salidas son las de esas pruebas.
Puntos clave
- CrowdSec separa detección (agente + LAPI) de bloqueo (bouncers): la misma fuente de decisiones puede alimentar un bouncer HTTP en Traefik y otro de red en iptables a la vez.
- El instalador de la 1.8 detecta tus servicios y escribe su acquisition en
/etc/crowdsec/acquis.d/; lo que no detecta, como los logs de Traefik, lo añades tú con la etiqueta correcta. - El WAF (componente AppSec) necesita dos collections: con
appsec-virtual-patchingsola, CrowdSec no arranca. - La remediación con captcha (Cloudflare Turnstile) evita banear a usuarios legítimos en escenarios de fuerza bruta.
- La blocklist comunitaria entregó 15.000 IPs a la instalación de prueba en su primera descarga.
- En un VPS de hobby con una sola capa que proteger, fail2ban sigue siendo más simple; CrowdSec compensa a partir de dos o tres capas.
Por qué vale la pena el cambio desde fail2ban
La diferencia más importante es arquitectónica. fail2ban lee logs, decide y ejecuta una regla de iptables en el mismo proceso. CrowdSec separa esas responsabilidades:
- El agente lee logs y emite decisiones a la LAPI (una API REST local que, por defecto, escucha en
127.0.0.1:8080). - Los bouncers (la documentación actual los llama componentes de remediación) consultan la LAPI y ejecutan el bloqueo, ya sea en el firewall, en un proxy inverso o en el propio servidor web.
Esta separación tiene consecuencias prácticas. Puedes tener un bouncer en el firewall para SSH y otro en Traefik para HTTP, y ambos actúan sobre las mismas decisiones: cambias la detección sin tocar el bloqueo. Y si contribuyes tus detecciones a la comunidad, recibes a cambio una lista de IPs que la red ha identificado como maliciosas.
La segunda diferencia es la expresividad. fail2ban usa expresiones regulares sobre líneas de log; CrowdSec usa scenarios (reglas declarativas en YAML que combinan qué detectar, con qué umbral, en qué ventana de tiempo y cómo agrupar coincidencias). El scenario crowdsecurity/ssh-bf, por ejemplo, es un cubo de capacidad 5 que pierde un evento cada 10 s.
Instalación del agente
En Debian o Ubuntu, añade el repositorio y comprueba qué versión va a instalar apt:
curl -s https://install.crowdsec.net | sudo sh
apt-cache policy crowdsec
sudo apt install crowdsec
La comprobación importa porque las distribuciones se quedaron en la 1.4.6. Debian 13 ofrece la 1.4.6-10+b4 y Ubuntu 24.04 la 1.4.6-6ubuntu0.24.04.2; con el repositorio añadido, el candidato pasa a ser la 1.8.1. En Ubuntu con ESM puede hacer falta subir la prioridad del repositorio, como explica la documentación de instalación[2]. Probé la instalación completa en Debian; en Ubuntu 24.04 solo comprobé el candidato.
Si vienes de la 1.7, actualiza: la versión 1.8.0[3] corrigió dos vulnerabilidades de denegación de servicio en las fuentes de datos HTTP y de auditoría de Kubernetes.
Al instalarse, el paquete registra la máquina en la LAPI y en la API central (CAPI) y ejecuta cscli setup, que detecta los servicios presentes. En la prueba detectó SSH y el sistema, instaló sus collections y escribió setup.sshd.yaml y setup.linux.yaml en /etc/crowdsec/acquis.d/. Confírmalo así:
sudo cscli version
sudo systemctl status crowdsec
version: v1.8.1-debian-pragmatic-arm64-909b5157
Codename: alphaga
BuildDate: 2026-09-03_10:56:41
GoVersion: 1.26.3
El agente y la LAPI corren en el mismo proceso, escuchando en localhost, y systemctl status debe mostrar active (running).
Collections: trabajo ahorrado desde el primer día
Una collection (paquete que agrupa parsers, los traductores de un formato de log concreto, y scenarios listos para una tecnología) evita escribir reglas desde cero. El instalador ya puso las de Linux y SSH. Para un stack típico con Traefik, WordPress y Gitea:
sudo cscli collections install crowdsecurity/traefik crowdsecurity/wordpress
sudo cscli collections install LePresidente/gitea
La de Gitea la publica un autor de la comunidad como LePresidente/gitea. El nombre crowdsecurity/gitea de la versión anterior de esta guía no existe: cscli responde can't find 'crowdsecurity/gitea' in collections.
La de WordPress detecta fuerza bruta en el login, enumeración de autores y sondeos de wp-config.php. En pocos días habrás revisado qué scenarios se disparan con tu tráfico real.
Decirle al agente qué logs leer
Este es el paso que más se olvida. La acquisition (la configuración que le dice al agente qué leer y con qué etiqueta) va en ficheros sueltos dentro de /etc/crowdsec/acquis.d/. Para Traefik, crea traefik.yaml:
source: file
filenames:
- /var/log/traefik/access.log
force_inotify: true
labels:
type: traefik
Sin force_inotify, si el log aún no existe cuando arranca CrowdSec, el agente no vigila el directorio (lo advierte la documentación de la fuente file[4]). Me pasó en la prueba; con la opción activa, el log creado después se leyó sin reiniciar.
Para SSH, el instalador ya generó esto en setup.sshd.yaml:
source: journalctl
journalctl_filter:
- _SYSTEMD_UNIT=ssh.service
labels:
type: syslog
La versión anterior de esta guía tenía dos errores aquí. La fuente se llama journalctl, no journald. Y en Debian y Ubuntu la unidad es ssh.service: filtrar por sshd.service, que es solo un alias, devolvió -- No entries --.
La etiqueta type no es arbitraria: los parsers filtran por ella. El de Traefik acepta cualquier valor que empiece por traefik, pero con type: proxy todas las líneas fallan sin un error en el log. cscli explain lo delata:
tail -1 /var/log/traefik/access.log | sudo cscli explain -f- --type proxy
├ s01-parse
| ├ 🔴 crowdsecurity/appsec-logs
| ├ 🔴 crowdsecurity/sshd-logs
| ├ 🔴 crowdsecurity/sshd-success-logs
| └ 🔴 crowdsecurity/traefik-logs
└-------- parser failure 🔴
Tras cada edición, ejecuta sudo crowdsec -t && sudo systemctl reload crowdsec. La unidad de systemd valida la configuración y envía SIGHUP al proceso, sin reiniciarlo. En la prueba, sudo cscli metrics show acquisition marcó 3.61k líneas leídas y parseadas del log de Traefik.
Diagnóstico: qué ver los primeros días
Tres comandos que conviene convertir en rutina:
sudo cscli alerts list: alertas disparadas (detecciones).sudo cscli decisions list: decisiones locales activas. Con-amuestra también las de la blocklist comunitaria.sudo cscli metrics: todas las tablas;cscli metrics show acquisitionmuestra solo una.
Si llevas más de 24 horas con el agente activo y ninguno de estos comandos muestra actividad, tu acquisition probablemente no está leyendo lo que crees.
Los bouncers: de detección a bloqueo efectivo
CrowdSec detecta, pero no bloquea nada por sí solo. Para Traefik, la documentación de CrowdSec[5] remite al plugin maxlerebourg/crowdsec-bouncer-traefik-plugin[6], que mantiene la comunidad. Si todavía no tienes el proxy, parte de la guía de instalación de Traefik con Docker Compose.
La versión estable del plugin es la 1.7.1, del 31 de julio de 2026. Se declara en la configuración estática de Traefik:
entryPoints:
web:
address: ":80"
forwardedHeaders:
trustedIPs:
- 172.16.0.0/12
- 192.168.0.0/16
experimental:
plugins:
bouncer:
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
version: v1.7.1
El bloque forwardedHeaders solo hace falta con otro proxy o una CDN delante, y lleva los rangos de ese proxy. Sin él, Traefik reescribe X-Forwarded-For y el plugin no ve la IP del cliente: en la prueba, una IP baneada siguió recibiendo 200 hasta que lo añadí.
Genera la clave del bouncer en el host; cscli la imprime una sola vez:
sudo cscli bouncers add traefik-bouncer
Y cópiala en el middleware de la configuración dinámica:
http:
middlewares:
crowdsec:
plugin:
bouncer:
enabled: true
crowdsecMode: stream
crowdsecLapiHost: 172.17.0.1:8080
crowdsecLapiKey: tu_clave_de_bouncer
crowdsecAppsecEnabled: true
crowdsecAppsecHost: 172.17.0.1:7422
forwardedHeadersTrustedIPs:
- 172.16.0.0/12
- 192.168.0.0/16
El paquete deja la LAPI en 127.0.0.1:8080, que un Traefik en contenedor no alcanza. Cambia listen_uri en /etc/crowdsec/config.yaml a la IP de docker0 (172.17.0.1 en la prueba; compruébala con ip -4 addr show docker0). Actualiza también esa URL en local_api_credentials.yaml, que apuntaba a 127.0.0.1. Lo mismo vale para el api_url de /etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml cuando instales el bouncer de más abajo.
Con crowdsecMode: stream, el plugin guarda las IPs bloqueadas en caché y las refresca cada 60 s; el modo por defecto, live, consulta la LAPI por cada IP que no tiene en caché. Medí tres rondas de 400 peticiones con la máquina cargada (load average de 46 en 18 núcleos). La mediana pasó de 0,19–0,20 ms sin middleware a 0,23–0,25 ms con el plugin.
Para SSH y los servicios que no son web, añade el firewall bouncer (existe también la variante para nftables):
sudo apt install crowdsec-firewall-bouncer-iptables
La versión 0.0.36 detecta el CrowdSec local, genera su propia clave y crea la cadena CROWDSEC_CHAIN con conjuntos ipset. En menos de un minuto cargó las 15.000 IPs de la blocklist comunitaria. Ahora tienes dos bouncers compartiendo la misma fuente de decisiones.
Activar el WAF: componente AppSec y virtual patching
Los bouncers bloquean IPs; el componente AppSec inspecciona cada petición HTTP que le reenvía Traefik y responde si hay que bloquearla. Instala las dos collections que pide la guía rápida del WAF con Traefik[7]:
sudo cscli collections install crowdsecurity/appsec-virtual-patching \
crowdsecurity/appsec-generic-rules
Las dos son obligatorias: la configuración crowdsecurity/appsec-default carga reglas experimental-* que solo trae la segunda. Con appsec-virtual-patching sola, CrowdSec se detuvo al arrancar con no appsec-rules found for pattern crowdsecurity/experimental-*.
Declara la fuente en /etc/crowdsec/acquis.d/appsec.yaml, en la misma IP que la LAPI:
source: appsec
listen_addr: 172.17.0.1:7422
appsec_configs:
- crowdsecurity/appsec-default
labels:
type: appsec
Aplica el cambio con sudo crowdsec -t && sudo systemctl restart crowdsec; usé restart porque también cambié las direcciones de escucha. Después, pide un .env, que bloquea la regla vpatch-env-access:
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/.env
sudo cscli metrics show appsec
200
403
+---------------------------------------------+
| Appsec '172.17.0.3:7422/' Rules Metrics |
+---------------------------------+-----------+
| Rule ID | Triggered |
+---------------------------------+-----------+
| crowdsecurity/vpatch-env-access | 1 |
+---------------------------------+-----------+
La IP 172.17.0.3 era la del contenedor que hacía de host. Un bloqueo de AppSec afecta solo a esa petición. El ban llega cuando una IP dispara dos reglas distintas en 60 s: el scenario crowdsecurity/appsec-vpatch desborda y el perfil por defecto la banea 4 horas, como pasó al pedir /.env y /.git/config.
Esa inspección tiene coste. En la misma máquina cargada, la mediana subió a 1,7 ms por petición, con un p95 de entre 7 y 10 ms.
La 1.8.0 añadió a este componente la detección de bots, en alfa según la documentación de detección de bots[8]. No la probé aquí; la cubre la guía de detección de bots con CrowdSec 1.8.
Remediación con captcha: no todo es ban
El error clásico de un WAF es banear todo lo sospechoso y descubrir a la semana que estabas bloqueando clientes legítimos. CrowdSec permite emitir decisiones de tipo captcha en lugar de ban, y el bouncer de Traefik muestra entonces un desafío de Cloudflare Turnstile[9] en lugar de cortar la conexión.
Esas decisiones salen de /etc/crowdsec/profiles.yaml. Este perfil, delante del de ban que trae el paquete, pide captcha para cualquier scenario con http en el nombre:
name: captcha_remediation
filters:
- >-
Alert.Remediation == true && Alert.GetScope() == "Ip"
&& Alert.GetScenario() contains "http"
decisions:
- type: captcha
duration: 4h
on_success: break
---
En el middleware, añade el proveedor y sus claves:
captchaProvider: turnstile
captchaSiteKey: tu_site_key_de_turnstile
captchaSecretKey: tu_secret_key_de_turnstile
captchaFilePath: /captcha.html
El plugin no incluye captcha.html: descárgalo de su repositorio y móntalo en el contenedor. Probé con las claves de prueba[10] de Cloudflare, que siempre validan. Veinticinco líneas 404 inyectadas en el log acabaron en una decisión captcha de http-probing, y una IP con captcha llegó a la aplicación tras enviar el token.
El patrón que funciona bien en producción:
- Fuerza bruta (alguien probando contraseñas): captcha. El usuario legítimo lo resuelve y sigue.
- Exploits conocidos (CVEs como CVE-2021-44228, o accesos a rutas sensibles): ban directo. Un bot de exploit no resuelve captchas.
Turnstile no cuesta nada: según la página de planes de Cloudflare[11], el plan Free admite hasta 20 widgets y desafíos ilimitados.
El valor real de la blocklist comunitaria
Ya no hace falta cscli capi register: el paquete registra la instalación en la CAPI, y sudo cscli capi status lo confirma con Sharing signals is enabled. Así entras en la red comunitaria que mantiene CrowdSec, la empresa detrás del proyecto: envías tus detecciones y recibes IPs que la red ha identificado como maliciosas.
El tamaño depende de lo que aportes, según la documentación de la blocklist comunitaria[12]: 3.000 IPs sin contribuir, 15.000 contribuyendo y sin límite en los planes de pago. La instalación de prueba recibió 15.000 en su primera descarga (7.691 de ssh:bruteforce, 6.408 de generic:scan y 901 de ssh:exploit), adaptadas a sus scenarios.
Matiz ético: al compartir detecciones contribuyes a una defensa colectiva, pero también envías información sobre tu tráfico. Si tus exigencias de privacidad no lo permiten, sharing: false bajo api.server.online_client corta el envío, a cambio de una blocklist más pequeña.
Monitorización
CrowdSec expone métricas Prometheus en un endpoint HTTP local, por defecto en 127.0.0.1:6060/metrics (puedes verificarlo con la documentación oficial de métricas[13]). Si ya monitorizas el servidor con algo como la guía de Netdata en Docker, este endpoint encaja igual de bien en ese panel. Métricas útiles:
cs_bucket_overflowed_total: detecciones por scenario (la versión anterior citabacs_bucket_overflow_count, que la 1.8.1 no expone).cs_active_decisions: decisiones activas por origen y acción.cs_appsec_block_total: peticiones bloqueadas por AppSec.
El repositorio oficial de dashboards de Grafana[14] declara compatibilidad hasta la serie 1.5, así que revisa sus paneles con la 1.8. La alerta más importante es la ausencia de métricas durante más de cinco minutos: el agente se paró o la acquisition se rompió.
Whitelists y errores comunes
Antes de bloquear nada en serio, protege tus propias IPs: tu oficina, la VPN, el CI/CD que despliega, los monitores externos. Desde la 1.6.8, la vía recomendada son las allowlists de cscli, que aceptan IPs y rangos CIDR y no necesitan reinicio:
sudo cscli allowlists create oficina -d "IPs propias"
sudo cscli allowlists add oficina 203.0.113.0/24 -d "red de la oficina"
added 1 values to allowlist oficina
1 decisions deleted by allowlists
Al añadir el rango, CrowdSec borró el ban que ya tenía una IP de esa red y rechazó otro que intenté añadir después. Según la guía de whitelists[15], las allowlists cubren también AppSec y los scenarios. Para filtrar patrones, como un GET /health, crea tu propio fichero en /etc/crowdsec/parsers/s02-enrich/ en vez de editar whitelists.yaml, que gestiona el hub.
Otro error frecuente: editar un fichero y no aplicarlo. Da por hecho que CrowdSec no detecta los cambios en caliente: sudo crowdsec -t && sudo systemctl reload crowdsec tras cada edición es disciplina básica.
Cuándo no compensa CrowdSec
Hay escenarios donde fail2ban sigue siendo más simple y adecuado:
- Servidor único con bajo tráfico y sin necesidad de compartir inteligencia entre nodos.
- Sin Traefik (sin plugin HTTP) y con una sola capa que proteger.
CrowdSec empieza a compensar cuando tienes más de una capa (web, SSH, aplicaciones) o cuando la blocklist comunitaria corta ruido de forma medible. También cuando quieres integrarlo con Ansible para gestionar allowlists y configuración de forma centralizada en más de un servidor.
Mi recomendación
Si vas a probarlo, hazlo con un despliegue progresivo:
- Instala el agente, revisa la acquisition generada, añade la de tus servicios y déjalo una semana en modo detección sin bouncer.
- Revisa qué se dispara, ajusta scenarios si hay ruido, añade allowlists.
- Solo entonces activa el primer bouncer (Traefik) y el componente AppSec.
- Espera otra semana y añade la remediación con captcha para fuerza bruta.
- Por último, decide si mantienes el envío de señales a la CAPI, que el paquete deja activado.
Llegar a este punto de madurez lleva dos o tres semanas de convivencia con la herramienta. La inversión merece la pena para cualquier stack con exposición real a internet.
Preguntas frecuentes
¿Cómo saber si CrowdSec está bloqueando tráfico de verdad?
Ejecuta sudo cscli decisions list: si aparecen filas con IPs y un tipo de decisión (ban o captcha), hay bloqueos locales activos. La vista por defecto oculta la blocklist comunitaria; añade -a para verla. Si la lista local sigue vacía cuando el agente lleva horas leyendo tráfico normal, revisa primero la acquisition con sudo cscli metrics show acquisition antes de sospechar del bouncer.
¿Necesito Traefik para usar CrowdSec?
No. El agente y la LAPI funcionan igual sin Traefik; lo que cambia es el bouncer. Sin proxy inverso puedes usar el firewall bouncer con iptables o nftables para bloquear a nivel de red, y el WAF funciona también con los bouncers de Nginx, OpenResty o HAProxy.
¿La blocklist comunitaria de CrowdSec es gratis?
Sí. El paquete registra la instalación en la CAPI y recibes sin coste la versión Lite, de hasta 3.000 IPs, o la completa, de 15.000, si contribuyes con tus detecciones de forma habitual. Los planes de pago añaden la versión Premium, sin límite de tamaño, pero no son necesarios para el uso descrito en esta guía.
Fuentes
- CrowdSec
- documentación de instalación
- versión 1.8.0
- documentación de la fuente file
- documentación de CrowdSec
- maxlerebourg/crowdsec-bouncer-traefik-plugin
- guía rápida del WAF con Traefik
- documentación de detección de bots
- Cloudflare Turnstile
- claves de prueba
- página de planes de Cloudflare
- documentación de la blocklist comunitaria
- documentación oficial de métricas
- repositorio oficial de dashboards de Grafana
- guía de whitelists
- notas de la versión 1.8.1