Configurar fail2ban con webhooks y Telegram en Ubuntu 22.04
Redes & Segurança · Por Kevin Marcondes · Publicado el · 8 min de lectura
En este tutorial configurarás fail2ban para que dispare webhooks y envíe alertas a Telegram en Ubuntu 22.04. Crearemos un script de notificación, registraremos una action personalizada y lo aplicaremos en una jail de SSHD. El objetivo es bloquear intentos de fuerza bruta y avisarte en tiempo real, de forma simple y reproducible.
Prerequisitos, objetivos e instalación de fail2ban
Necesitas un Ubuntu 22.04 con acceso root y salida HTTP/HTTPS. Ten un bot de Telegram (token y chat ID) y, opcionalmente, un endpoint de webhook. Cuidado: reglas incorrectas pueden bloquear tu IP. Prueba desde otro host o utiliza ignoreip.
Objetivos: instalar fail2ban, crear un script de notificación (webhook + Telegram), registrar una action y aplicar todo en una jail de SSHD.
Si aún no tienes un firewall básico, consulta Cómo configurar firewall en Ubuntu con UFW. Para un hardening más amplio, revisa el checklist de seguridad para VPS Linux.
- Acceso root o sudo sin contraseña
- curl instalado para llamadas HTTP
- Bot de Telegram (token) y chat ID
- Opcional: URL de webhook y secreto (HMAC)
# Atualize pacotes, instale e habilite
sudo apt update && sudo apt install -y fail2ban curl
sudo systemctl enable --now fail2ban
# Verifique versão, status e logs
fail2ban-client -V || true
sudo systemctl status fail2ban --no-pager
sudo tail -n 50 /var/log/fail2ban.log || true
Visión general del flujo (qué dispara qué)
Fail2ban lee logs. Cuando un patrón de fallo supera el límite, aplica el ban (por ejemplo: iptables) y ejecuta una action. Crearemos una action que llame a un script. El script enviará un POST a tu webhook y alertará en Telegram.
Puedes adaptar el flujo a Nginx, Postfix y otros servicios. Para reducir ataques SSH, evalúa un bastión: Cómo configurar un bastión SSH en Ubuntu 22.04.
| Paso | Componente | Ejemplo |
|---|---|---|
| Evento de falla | Registro (sshd) | Múltiples contraseñas incorrectas |
| Detección | Filtro + jail (fail2ban) | maxretry alcanzado |
| Bloqueo | Acción de ban (iptables) | DROP en la IP ofensiva |
| Notificación | Action personalizada | Script llama webhook y Telegram |
Telegram: crear bot y guardar variables de forma segura
Crea un bot en Telegram (vía BotFather) y obtén el token. Encuentra tu chat ID después de enviar /start al bot. Guardaremos todo en un archivo solo‑lectura para root.
También permitiremos configurar un webhook opcional y un secreto HMAC. Mantén el archivo con permiso 600.
- TELEGRAM_BOT_TOKEN: token del bot
- TELEGRAM_CHAT_ID: ID del chat/grupo/canal
- WEBHOOK_URL: URL de automatización (opcional)
- WEBHOOK_SECRET: clave para firmar payload (opcional)
# Crie o arquivo de variáveis sensíveis
sudo tee /etc/fail2ban/telegram.env >/dev/null <<'EOF'
TELEGRAM_BOT_TOKEN="coloque_o_token_aqui"
TELEGRAM_CHAT_ID="coloque_o_chat_id_aqui"
# Opcional: envie também para um webhook de automação
WEBHOOK_URL=""
WEBHOOK_SECRET=""
EOF
# Restrinja permissões
sudo chown root:root /etc/fail2ban/telegram.env
sudo chmod 600 /etc/fail2ban/telegram.env
Script de notificación: webhook + Telegram
El script recibe datos de fail2ban (IP, jail y evento), monta un JSON y envía: 1) un POST a tu webhook, con firma HMAC opcional; 2) un mensaje a Telegram. Prueba manualmente antes de integrar.
El mensaje a Telegram es texto simple. Para automatizaciones, integra el webhook en n8n, Zapier o Make.
- Firma HMAC-SHA256 opcional en el header X-Signature
- Payload JSON claro: ip, jail, evento, timestamps
- Salidas independientes: webhook y Telegram
sudo tee /usr/local/bin/f2b_notify.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
ENV_FILE="/etc/fail2ban/telegram.env"
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
IP="${1:-}"
JAIL="${2:-}"
LOGPATH="${3:-}"
EVENT="${4:-ban}"
FAILURES="${5:-}"
FINDTIME="${6:-}"
BANTIME="${7:-}"
TS="$(date -Iseconds)"
HOSTNAME="$(hostname -f 2>/dev/null || hostname)"
# Monta payload JSON mínimo
PAYLOAD=$(cat <<JSON
{
"host": "${HOSTNAME}",
"jail": "${JAIL}",
"ip": "${IP}",
"event": "${EVENT}",
"failures": "${FAILURES}",
"findtime": "${FINDTIME}",
"bantime": "${BANTIME}",
"logpath": "${LOGPATH}",
"timestamp": "${TS}"
}
JSON
)
# 1) Envio para webhook (opcional)
if [[ -n "${WEBHOOK_URL:-}" ]]; then
SIG=""
if [[ -n "${WEBHOOK_SECRET:-}" ]]; then
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -binary | base64)
fi
curl -fsS -X POST "$WEBHOOK_URL" \
-H 'Content-Type: application/json' \
${SIG:+-H "X-Signature: ${SIG}"} \
--data-raw "$PAYLOAD" || true
fi
# 2) Envio para Telegram (opcional)
if [[ -n "${TELEGRAM_BOT_TOKEN:-}" && -n "${TELEGRAM_CHAT_ID:-}" ]]; then
TEXT="[fail2ban] ${EVENT^^} em ${JAIL} — IP ${IP} — host ${HOSTNAME} — ${TS}"
curl -fsS -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-H 'Content-Type: application/json' \
-d "{\"chat_id\":\"${TELEGRAM_CHAT_ID}\",\"text\":\"${TEXT}\"}" || true
fi
EOF
sudo chmod +x /usr/local/bin/f2b_notify.sh
Registrar la action personalizada en fail2ban
Crea una action en action.d para que la jail pueda llamarla en cada ban y unban. Pasaremos al script las variables necesarias.
Mantendremos actionban y actionunban. El ban real (iptables) quedará definido en la jail.
# /etc/fail2ban/action.d/f2b-notify-webhook-telegram.conf
[Definition]
actionstart =
actionstop =
# Evento de ban
actionban = /usr/local/bin/f2b_notify.sh "<ip>" "<name>" "<logpath>" "ban" "<failures>" "<findtime>" "<bantime>"
# Evento de unban (informativo)
actionunban = /usr/local/bin/f2b_notify.sh "<ip>" "<name>" "<logpath>" "unban" "0" "0" "0"
[Init]
name = default
Jail de SSHD usando iptables y la nueva action
Ahora crearemos una jail para sshd. Bloquea vía iptables y dispara nuestra action de notificación. Añade tu IP en ignoreip para no auto‑banearte.
Adapta maxretry, findtime y bantime según tu riesgo y volumen de accesos.
- backend systemd funciona bien en Ubuntu 22.04
- iptables-nft es estándar; iptables-multiport sigue siendo válido
- ignoreip acepta listas y CIDRs
# /etc/fail2ban/jail.d/sshd.local
[sshd]
enabled = true
port = 22
logpath = %(sshd_log)s
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16
# Ação de bloqueio (iptables)
banaction = iptables-multiport
# Notificações
action = f2b-notify-webhook-telegram
Pruebas: recargar, simular fallos y validar alertas
Es hora de probar. Recarga fail2ban, verifica la jail sshd y simula inicios de sesión con contraseña errónea desde otro host. Confirma el ban, la ejecución de la action y la recepción de alertas en Telegram y en el webhook.
También puedes forzar un unban para validar la alerta de desbloqueo.
- Usa una máquina separada para probar fallos de SSH
- Monitorea /var/log/fail2ban.log en tiempo real
- Si nada llega a Telegram, valida token y chat ID
# Recarregar e inspecionar
sudo fail2ban-client reload
sudo fail2ban-client status
sudo fail2ban-client status sshd
# Acompanhar logs
sudo tail -f /var/log/fail2ban.log &
# (Em outro host) force tentativas erradas de SSH
# ssh usuario@SEU_IP # digite senhas erradas
# Checar IPs banidos e desbanir para testar unban
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 1.2.3.4 # troque pelo IP de teste
Solución de problemas y mejoras útiles
Algunos problemas son comunes y fáciles de resolver. Aquí tienes consejos y extensiones del setup. Para observabilidad, considera métricas con Prometheus y dashboards con Grafana: revisa la guía en Prometheus y Grafana con Docker Compose en VPS.
- Sin alertas: verifica permisos 600 en /etc/fail2ban/telegram.env y que el script sea ejecutable.
- Proxy corporativo: exporta http_proxy/https_proxy para el servicio.
- UFW activo: iptables-multiport suele coexistir; si hay conflicto, usa ufw como banaction.
- Mensaje de Telegram con caracteres extraños: simplifica el TEXT.
- Webhook no recibe: prueba manual con curl y valida retorno HTTP 2xx.
- Reduce ruido: ajusta filtros, maxretry y findtime; considera una acción de ban incremental.
- Firma: valida X-Signature en tu flujo (n8n, Zapier, Make).
# Teste manual do webhook (substitua URL)
WEBHOOK_URL="https://example.com/webhook"
payload='{"hello":"world"}'
curl -v -X POST "$WEBHOOK_URL" -H 'Content-Type: application/json' --data-raw "$payload"
Preguntas frecuentes
¿Funciona con otros servicios además de SSH (sshd)?
Sí. Crea o habilita jails para Nginx, Postfix y Apache, apuntando al log correcto y ajustando maxretry, findtime y bantime. Reutiliza la misma action para estandarizar las alertas.
¿Cómo encuentro mi chat ID en Telegram?
Inicia conversación con tu bot, envía un mensaje y usa un bot utilitario para obtener el chat ID. También puedes leer el JSON de update de la API de Telegram tras enviar el primer mensaje.
¿UFW y fail2ban pueden ejecutarse juntos?
Generalmente sí. Fail2ban aplica reglas temporales mientras UFW mantiene la política base. Si hay conflicto, cambia la acción de ban a ufw en lugar de iptables-multiport.
¿Cómo evito banearme por error?
Usa ignoreip con tu IP fija o un bloque confiable. Prueba desde otra máquina y, si es necesario, reduce temporalmente el bantime. Si pierdes acceso, usa la consola y ejecuta unbanip.
¿Puedo firmar el payload del webhook para validar el origen?
Sí. Define WEBHOOK_SECRET. El script calcula un HMAC‑SHA256 del cuerpo y lo envía en el header X-Signature en base64. En el receptor, recalcula y compara para validar.
¿Cómo integrar con n8n, Zapier o Make?
Apunta WEBHOOK_URL a un webhook público creado en la herramienta. La automatización puede enrutar alertas a e‑mail, SMS, Slack o abrir tickets. Valida X-Signature antes de procesar.
¿Necesitas adaptar este setup a tu entorno?
¿Quieres ampliarlo a otras jails, reducir falsos positivos y estandarizar alertas? Revisemos filtros, actions y automatizaciones de tu stack.
Hablar sobre seguridad y automatizaciónVer también
- Tutorial: implementar Canary releases con Traefik en Docker Compose usando headers y weighted routing para despliegues graduales de aplicaciones PHP
- Tutorial: configurar HAProxy con Let's Encrypt y healthchecks para balanceo de tráfico entre contenedores Docker en VPS (paso a paso)
- Tutorial práctico: implementar mTLS entre Nginx y microservicios usando smallstep CA en Docker Compose
- Tutorial: configurar cgroup v2 y systemd ResourceControl para limitar CPU, memoria e I/O de contenedores Docker en Debian