Por Qué la Limitación de Velocidad es Importante

Todo servidor web público está sujeto a picos de tráfico, scrapers automatizados, intentos de fuerza bruta y ataques de denegación de servicio distribuido (DDoS). Sin limitación de velocidad, un solo cliente abusivo puede agotar la CPU, memoria y descriptores de archivo de su servidor, haciendo el servicio inaccesible para usuarios legítimos.

La limitación de velocidad integrada de Nginx proporciona una capa de defensa ligera y de alto rendimiento que opera a nivel de proxy inverso, antes de que las solicitudes lleguen a su aplicación. Usando los módulos ngx_http_limit_req_module y ngx_http_limit_conn_module, puede aplicar tasas de solicitud por IP o por usuario, límites de conexión y permisos de ráfaga con mínima configuración.

Esta guía muestra configuraciones prácticas de limitación de velocidad para endpoints de API, páginas de inicio de sesión, activos estáticos y protección general del sitio.

Requisitos Previos

  • Nginx 1.18+ instalado (ambos módulos están compilados por defecto).
  • Acceso sudo o root para editar archivos de configuración de Nginx.
  • Familiaridad básica con la sintaxis de configuración de Nginx (http, server, location).
  • Una herramienta de prueba como curl, Apache Bench (ab) o wrk.

Entendiendo el Algoritmo de Cubo con Fugas

La limitación de velocidad de Nginx usa el algoritmo de cubo con fugas (leaky bucket). Imagine un cubo con un pequeño agujero en el fondo:

  • Las solicitudes llenan el cubo desde arriba.
  • El cubo drena a una tasa fija (su tasa configurada, ej. 10 solicitudes/segundo).
  • Si el cubo se desborda, las solicitudes excedentes son rechazadas o encoladas (burst).

Solución Paso a Paso

1. Definir una Zona de Limitación

En su nginx.conf (dentro del bloque http), defina una zona de memoria compartida:

http {
    # Zona "api": por IP del cliente, 10MB almacenamiento, 10 solicitudes/segundo
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    # Zona "login": más estricta, 5 solicitudes/minuto
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

    # Zona "general": moderada, 30 solicitudes/segundo
    limit_req_zone $binary_remote_addr zone=general:10m rate=30r/s;
}

2. Aplicar Límites a Ubicaciones

server {
    listen 80;
    server_name ejemplo.com;

    limit_req zone=general burst=50 nodelay;
    limit_req_status 429;

    location /api/auth/login {
        limit_req zone=login burst=3 nodelay;
        proxy_pass http://backend;
    }

    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://backend;
    }

    location /static/ {
        limit_req off;
        alias /var/www/static/;
    }
}

Entendiendo burst y nodelay:

  • burst=N: Permite hasta N solicitudes adicionales sobre el límite que se encolan en lugar de rechazarse inmediatamente.
  • nodelay: Procesa las solicitudes de ráfaga inmediatamente sin demora.
  • delay=N: (Nginx 1.15.7+) Híbrido: las primeras N solicitudes de ráfaga se procesan inmediatamente, el resto se demoran.

3. Configurar Limitación de Conexiones

http {
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    server {
        limit_conn addr 10;
        limit_conn_status 429;

        location /descargas/ {
            limit_conn addr 2;
            limit_rate 500k;
        }
    }
}

4. Excluir IPs Confiables

http {
    geo $limit_key {
        default         $binary_remote_addr;
        10.0.0.0/8      "";
        192.168.1.0/24  "";
        203.0.113.50    "";
    }

    limit_req_zone $limit_key zone=api:10m rate=10r/s;
}

5. Respuestas de Error Personalizadas

error_page 429 = @rate_limited;

location @rate_limited {
    default_type application/json;
    return 429 '{"error": "rate_limit_exceeded", "message": "Demasiadas solicitudes. Intente nuevamente en unos segundos.", "retry_after": 1}';
}

6. Probar la Configuración

sudo nginx -t
sudo systemctl reload nginx

# Probar con Apache Bench
ab -n 100 -c 10 http://ejemplo.com/api/data

# O con curl en un bucle
for i in $(seq 1 20); do
    echo "Solicitud $i: $(curl -s -o /dev/null -w '%{http_code}' http://ejemplo.com/api/data)"
done

Errores Comunes y Casos Especiales

  • Cadenas de proxy inverso: Si Nginx está detrás de un balanceador de carga o CDN, $binary_remote_addr será la IP del proxy. Use el módulo realip para extraer la IP real del cliente.
  • Direcciones IPv6: $binary_remote_addr es 16 bytes para IPv6 (vs 4 para IPv4). Dimensione las zonas apropiadamente.
  • Claves API en lugar de IPs: Para APIs autenticadas, puede usar un header como clave: limit_req_zone $http_x_api_key zone=apikey:10m rate=100r/s;

Prevención

  • Combine con un WAF: Use ModSecurity, Cloudflare o AWS WAF para defensa en profundidad.
  • Use fail2ban: Bloquee automáticamente IPs que excedan los límites persistentemente.
  • Monitoree con métricas: Exporte métricas con el módulo stub_status y alerte sobre tasas elevadas de 429.
  • Ajuste gradualmente: Comience con límites generosos y ajústelos según los patrones de tráfico observados.

Resumen

  • La limitación de velocidad de Nginx usa limit_req_zone/limit_req para tasas de solicitud y limit_conn_zone/limit_conn para límites de conexión.
  • El algoritmo de cubo con fugas suaviza los picos de tráfico en lugar de imponer conteos rígidos por segundo.
  • Configure siempre burst y nodelay para cargas de producción.
  • Use limit_req_status 429 para devolver el código HTTP 429 estándar.
  • Excluya IPs confiables con bloques geo y pruebe exhaustivamente antes de desplegar.

Artículos Relacionados