Proteger un sitio Nginx frente a un ataque de capa de aplicación (L7)

Publicado el 21/08/2026 Actualizado el 06/10/2026 49 visitas
Sécurité VPS Linux Nginx DDoS

No todos los ataques son iguales. Un ataque volumétrico busca saturar el enlace de red: es un atasco en la autopista, y de eso se encarga la protección de By-Hoster aguas arriba, sin que usted tenga que hacer nada.

Un ataque de aplicación, llamado de capa 7, es distinto. El tráfico sigue siendo modesto, pero cada petición es cara: una búsqueda, una página de inicio de sesión, un carrito. Para la red parecen visitantes normales. Solo en su servidor web se hace visible la naturaleza del tráfico, y por tanto ahí es donde hay que actuar.

¿Cómo sé qué está golpeando realmente mi servidor?

No cambie nada mientras no sepa qué está llegando. Un ajuste puesto al azar suele bloquear a sus visitantes reales sin molestar al atacante.

Las direcciones IP más activas:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Las URL más solicitadas:

awk -F'"' '{print $2}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

El tráfico reciente, para valorar la intensidad:

tail -n 100000 /var/log/nginx/access.log | awk '{print $4}' | uniq -c | tail -20

Busca un patrón: un puñado de direcciones muy habladoras, una única URL machacada, un agente de usuario idéntico en todas partes. Es ese patrón el que dicta la regla, y no al revés.

Compruebe también qué se satura realmente:

uptime
systemctl status php8.3-fpm --no-pager

A menudo no es Nginx quien cede, sino PHP o la base de datos que hay detrás.

¿Cómo limito el ritmo de peticiones por dirección en Nginx?

Nginx sabe contar peticiones por dirección y frenar las que superan un umbral. Las zonas se declaran en el bloque http (/etc/nginx/nginx.conf):

http {
    limit_req_zone  $binary_remote_addr zone=req_por_ip:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=conn_por_ip:10m;
}

Y se aplican en el bloque del sitio:

server {
    limit_req  zone=req_por_ip burst=20 nodelay;
    limit_conn conn_por_ip 20;
}

En la práctica:

Ajuste Efecto
rate=10r/s 10 peticiones por segundo y dirección en régimen normal
burst=20 tolera un pico de 20 peticiones por encima del ritmo
nodelay sirve el pico de inmediato en vez de repartirlo
limit_conn 20 20 conexiones simultáneas como máximo por dirección

Una zona de 10m memoriza unas 160 000 direcciones, de sobra.

burst sin nodelay encola las peticiones: el sitio se vuelve lento en lugar de rechazar. Con nodelay, un visitante normal que carga una página y sus veinte recursos pasa sin frenos, mientras que un robot insistente recibe un 503.

Proteja con más severidad las URL realmente caras en lugar de todo el sitio:

location = /wp-login.php {
    limit_req zone=req_por_ip burst=3 nodelay;
}

¿Cómo pruebo la configuración de Nginx antes de aplicarla?

Con nginx -t, que valida la sintaxis sin aplicar nada, y después una recarga en caliente en lugar de un reinicio.

nginx -t

Este comando valida la sintaxis sin interrumpir nada. Debe responder syntax is ok y después test is successful. Solo entonces:

systemctl reload nginx

reload recarga la configuración sin cortar las conexiones en curso, a diferencia de restart. En plena ataque, la diferencia importa.

Vigile lo que se está rechazando:

grep "limiting requests" /var/log/nginx/error.log | tail -20

Si aparecen sus propias direcciones o las de sus clientes, el límite es demasiado bajo. Súbalo.

¿Cómo sirvo menos veces la misma página?

La mejor forma de encajar un ataque suele ser dejar de recalcular la página en cada petición. Una página cacheada 60 segundos no cuesta casi nada, se pida las veces que se pida.

http {
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=sitio:50m inactive=10m;
}
location / {
    proxy_cache sitio;
    proxy_cache_valid 200 60s;
    proxy_cache_use_stale error timeout updating;
}

proxy_cache_use_stale es la línea que salva: si el backend deja de responder, Nginx sigue sirviendo la última versión conocida en lugar de un error.

En WordPress, PrestaShop o Laravel, un módulo de caché de aplicación logra lo mismo con menos efectos secundarios.

¿Cómo baneo a las direcciones reincidentes con fail2ban?

Limitar frena; banear detiene. fail2ban lee los registros y añade una regla de cortafuegos contra las direcciones que disparan el límite con demasiada frecuencia.

apt install fail2ban

En /etc/fail2ban/jail.local:

[nginx-limit-req]
enabled  = true
filter   = nginx-limit-req
logpath  = /var/log/nginx/error.log
maxretry = 10
findtime = 60
bantime  = 3600
systemctl restart fail2ban
fail2ban-client status nginx-limit-req

Leída en voz alta, la regla dice: una dirección que dispara 10 veces la limitación en 60 segundos queda bloqueada una hora.

¿Qué ajustes conviene evitar ante un ataque aplicativo?

Estos ajustes circulan mucho y hacen más daño que bien.

Evitar Por qué
Bloquear curl y wget por agente de usuario Un atacante cambia de agente en una línea. Usted rompe su supervisión, sus webhooks de pago y sus scripts de copia de seguridad.
client_max_body_size 1k Falla toda subida de imagen, todo formulario algo largo, toda actualización del CMS.
allow en una subred y luego deny all Cierra el sitio a todo Internet, visitantes incluidos. Reserve ese esquema para las URL de administración.
Banear países enteros por reflejo Muchos falsos positivos, y los atacantes alquilan máquinas en cualquier parte.
Desactivar los registros «por rendimiento» Pierde el único medio de entender qué le está pasando.

Una regla sencilla: toda medida que bloquee más ancho que el patrón observado se pagará en clientes perdidos.

¿Cuándo debo abrirnos un ticket?

Cuando el problema supera lo que puede resolver en la máquina: enlace saturado, ataque prolongado o miles de direcciones.

Abra un ticket si:

  • la máquina sigue inaccesible pese a estos ajustes;
  • el tráfico satura el enlace de red antes incluso de llegar a Nginx;
  • el ataque se prolonga y procede de miles de direcciones distintas.

Adjunte los extractos de registro del paso 1 y la franja horaria afectada. Es lo que nos permite actuar aguas arriba, en la red, donde usted no puede intervenir.

¿Le ha resultado útil este artículo?