Agente para servidores Linux
Vigila fail2ban y comparte las IPs atacantes con la red. Se instala con un comando.
¿No has usado nunca una consola? Tranquilo. Son 4 pasos y te explicamos cada uno como si fuera la primera vez.
Consigue tu «llave» (API key)
Entra en tu panel de ALMC SHIELD → Ajustes. Verás un código que empieza por
ab_live_…. Esa es tu API key: cópiala, la usarás en el paso 3. ¿Aún no tienes cuenta? Créala gratis aquí.Entra en tu servidor
«Entrar en el servidor» significa abrir una ventana negra donde se escriben comandos. Tienes dos formas:
- Si tu servidor tiene panel (aaPanel, Plesk, cPanel, ISPConfig…): busca el botón «Terminal» y ábrelo. Ya estás dentro.
- Si no tienes panel: en tu ordenador abre una terminal y escribe
ssh root@LA-IP-DE-TU-SERVIDOR(sustituye por la IP que te dio tu proveedor). Te pedirá la contraseña.
En Windows usaPowerShell(ya viene incluido) o el programa gratuito PuTTY. En Mac/Linux, la app «Terminal».Pega este único comando
Copia la línea de abajo, cambia
ab_live_XXXXXXXpor tu API key del paso 1, pégala en la ventana y pulsa Enter:curl -sSL https://almc.es/abuse-shield/install.sh | sudo bash -s -- --api-key=ab_live_XXXXXXXEso es todo. El instalador hace el resto solo: detecta tu sistema, instala el agente, lo arranca y lo deja vigilando.
Comprueba que funciona
Escribe esto para ver si está en marcha (debe decir
active (running)):systemctl status almc-shieldO más fácil: vuelve a tu panel de ALMC SHIELD → sección Servidores. En menos de un minuto verás aparecer tu servidor en la lista. 🎉
¡Listo! Tu servidor ya comparte y recibe IPs atacantes de toda la red ALMC SHIELD.
Requisitos y distribuciones soportadas
- Linux con
fail2ban ≥ 0.10instalado y funcionando. - Python 3.8+ (sin dependencias compiladas).
- systemd (bare-metal/VM) o Docker / Kubernetes.
- Salida HTTPS al puerto 443 hacia
almc.es. NO requiere puertos entrantes.
Configuración avanzada (config.ini)
El archivo /etc/almc-shield/config.ini permite ajustes finos:
[agent]
api_key = ab_live_XXXXXXX
api_url = https://almc.es/api/v1/abuse
hostname = web-01.example.com
[fail2ban]
log_path = /var/log/fail2ban.log
poll_seconds = 30
report_jails = sshd, nginx-botsearch, recidive
default_bantime = 3600
[blocklist]
download_enabled = true
refresh_seconds = 600
output_file = /etc/almc-shield/blocklist.txt
on_update_command = /usr/sbin/ipset restore -! < /etc/almc-shield/blocklist.txt
[network]
timeout_seconds = 30
retry_max = 5
proxy = | Sección | Clave | Default | Descripción |
|---|---|---|---|
| fail2ban | poll_seconds | 30 | Intervalo entre lecturas del log fail2ban. |
| fail2ban | default_bantime | 3600 | Bantime sugerido para reports sin valor explícito. |
| fail2ban | log_path | /var/log/fail2ban.log | Auto-detect en Alpine. |
| blocklist | refresh_seconds | 600 | Mín. recomendado: 300. |
| blocklist | on_update_command | (vacío) | Comando tras actualizar blocklist (ej. ipset restore). |
| network | retry_max | 5 | Reintentos con backoff exponencial antes del circuit breaker. |
systemctl reload almc-shield) sin perder la outbox de reports pendientes.Docker / Kubernetes
El agente también se distribuye como imagen Docker:
# docker-compose.yml
services:
almc-shield:
image: ghcr.io/almc-security/almc-shield:1.0
restart: unless-stopped
network_mode: host
volumes:
- /var/log/fail2ban.log:/var/log/fail2ban.log:ro
- /etc/almc-shield:/etc/almc-shield:ro
- almc-shield-state:/var/lib/almc-shield
environment:
- ALMC_API_KEY=ab_live_XXXXXXX
volumes:
almc-shield-state: Problemas frecuentes
Error auth_blocked
El servidor central rechazó la API key: tenant suspendido por billing, API key rotada/revocada (actualiza config.ini), o cuenta en quarantined (contacta soporte). Revisa /ca/dash/abuse-shield.
Error tls_failures creciente
- Reloj del sistema desfasado (
timedatectl status). - Firewall outbound bloqueando 443 hacia
almc.es. - Proxy corporativo sin configurar — establece
proxy = http://....
El agente no detecta nuevos bans
- Verifica que
log_pathapunta al log activo (Alpine:/var/log/fail2ban/fail2ban.log). - Permisos:
setfacl -m u:almc-shield:r /var/log/fail2ban.log. - Los
jailsque monitorizas deben estar enreport_jails.
Desinstalar
Eliminación limpia con un solo comando:
curl -sSL https://almc.es/abuse-shield/uninstall.sh | sudo bash Detiene el servicio, borra /opt/almc-shield/, /etc/almc-shield/ y /var/lib/almc-shield/, y elimina el usuario. NO toca tu fail2ban ni tus reglas iptables/ipset.
API REST y privacidad
| Método | Endpoint | Descripción | Auth |
|---|---|---|---|
| POST | /api/v1/abuse/report | El agente reporta un ban | Bearer |
| POST | /api/v1/abuse/events | Fuentes externas (WAF, IDS, plugins) reportan detecciones categorizadas | Bearer |
| POST | /api/v1/abuse/heartbeat | Keepalive del servidor | Bearer |
| GET | /api/v1/abuse/blocklist | Blocklist del tenant | Bearer |
| GET | /abuse/feed.txt | Feed global público (texto) | — |
| GET | /abuse/feed.json | Feed global público (JSON) | — |
El agente solo envía {ip baneada, jail, timestamp, hostname reportador}. NO enviamos logs raw, paths, contraseñas, payloads ni datos de tus usuarios. Base legal: interés legítimo (Art. 6.1.f RGPD). Detalle en Política de privacidad y DPA.
Fuentes externas: conecta tu WAF o tu IDS
Además del agente, cualquier sistema de detección tuyo puede reportar a Shield: ModSecurity, Cloudflare, Wordfence, un IDS propio… A diferencia de /report, aquí cada detección lleva su categoría de ataque normalizada, y eso es lo que permite que una inyección SQL pese más que un escaneo.
Autenticación: la misma API key que usa el agente. Límites: 600 peticiones/min por clave, 500 eventos y 256 KB por lote.
curl -sS -X POST https://almc.es/api/v1/abuse/events \
-H "Authorization: Bearer $ALMC_SHIELD_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"reporter_id":"modsec-web01","source":"modsecurity",
"events":[{"ip":"203.0.113.7","category":"sqli","rule_id":"942100",
"count":3,"seen_at":"2026-09-04T10:23:45Z"}]}' reporter_id lo eliges tú e identifica la fuente: no usamos la IP de origen, porque un Worker de Cloudflare sale por IPs distintas y varios plugins comparten la de un hosting. Máximo 25 fuentes por cuenta.
Categorías admitidas
| Severidad | Categorías |
|---|---|
| Crítica | rcesqliwebshelldeserialization |
| Alta | lfirfixssssrfxxeauth-bypassmalware-upload |
| Media | bruteforcecredential-stuffingenumerationspam |
| Baja | scannerbad-botprotocoldosother |
Usa other antes que descartar un evento: ninguna detección tuya debería perderse por no encontrar su etiqueta.
Cómo traducir lo que ya tienes
| Origen | Equivalencias |
|---|---|
| OWASP CRS | attack-sqli→sqli, attack-xss→xss, attack-rce y attack-injection-php→rce, attack-lfi→lfi, attack-rfi→rfi, attack-protocol→protocol, attack-reputation-scanner→scanner. rule_id = id de la regla. |
| Cloudflare | SQLi→sqli, XSS→xss, RCE→rce, File Inclusion→lfi, Scanner→scanner, Bot→bad-bot, Rate limit→dos. rule_id = ruleId del evento. |
| Wordfence | Brute force→bruteforce, SQL Injection→sqli, File Upload→malware-upload, Directory Traversal→lfi, Comment spam→spam. |
Detalles que te ahorrarán un mal rato
- El lote es todo o nada. Un solo evento inválido devuelve 422 y se descarta el lote entero. Filtra en origen las IPs privadas: un plugin tras un proxy que lea
REMOTE_ADDRmandaría10.xy tumbaría todos sus envíos. - No deduplicamos por evento. Reenviar la misma detección la cuenta dos veces. Agrupa por
(ip, categoría)en ventanas de ≥60 s y usacount. - Reintentos: ante 429 (respeta
Retry-After), 5xx o timeout, reintenta con la mismaIdempotency-Key. Ante 4xx, no reintentes: corrige el envío. Nunca generes una clave nueva para el mismo lote. Idempotency-Key: máximo 36 caracteres. Si la derivas de un hash, recórtala.seen_at: ISO 8601, preferiblemente conZ. Sin zona horaria se interpreta como UTC.
Qué NO aceptamos. Rechazamos con error cualquier evento que incluya path, url, payload, user_agent, cabeceras, cookies o datos de usuario. No es un filtro silencioso: recibes un 422 diciéndote qué campo sobra. La promesa de arriba —ni logs, ni rutas, ni contenido de peticiones— vale igual para este endpoint.









