kb.erickguedes.com
Nginx: Performance e Proxy Reverso

Rewrite e Rate Limiting

Aula 4 de 6

Rewrite e Redirecionamentos

Diretiva rewrite

# Sintaxe: rewrite regex substituição [flag];

# Redirecionamento simples
rewrite ^/old-page$ /new-page permanent;      # 301
rewrite ^/temp$ /other redirect;               # 302

# Redirecionamento de domínio
server {
    listen 80;
    server_name old-domain.com www.old-domain.com;
    rewrite ^(.*)$ http://new-domain.com$1 permanent;
}

# Remover prefixo de URL
rewrite ^/products/(.*)$ /item?id=$1 last;

# Redirecionar para HTTPS com rewrite
server {
    listen 80;
    server_name site.com;
    rewrite ^(.*)$ https://site.com$1 permanent;
}

Flags do rewrite

FlagSignificado
lastFinaliza o processamento de rewrites na location atual
breakFinaliza o processamento de rewrites sem validar novas locations
redirectRedirecionamento temporário (302)
permanentRedirecionamento permanente (301)

Diretiva return (preferível ao rewrite)

# return é mais eficiente que rewrite para redirecionamentos simples

# Redirecionamentos
return 301 http://new-domain.com$request_uri;
return 302 /temp-page.html;

# Respostas diretas
return 200 "OK";
return 404;
return 403 "Acesso negado";

# Redirecionar HTTP para HTTPS (forma mais eficiente)
server {
    listen 80;
    server_name site.com;
    return 301 https://site.com$request_uri;
}

# Redirecionar www para sem www
server {
    listen 80;
    server_name www.site.com;
    return 301 $scheme://site.com$request_uri;
}

# Redirecionar com preservação de query string
server {
    listen 80;
    server_name site.com;
    return 301 https://site.com$request_uri?$query_string;
}

try_files com Named Locations

# Named location (prefixo @)
server {
    root /var/www/site;

    location / {
        try_files $uri $uri/ @app;
    }

    location @app {
        proxy_pass http://backend:3000;
    }

    location /admin {
        try_files $uri $uri/ @admin_fallback;
    }

    location @admin_fallback {
        proxy_pass http://admin-backend:4000;
    }
}

Exemplos Práticos de Rewrite

server {
    listen 80;
    server_name blog.exemplo.com;

    # SEO: remover trailing slash
    rewrite ^/(.+)/$ /$1 permanent;

    # SEO: URL amigável
    rewrite ^/post/([0-9]+)/(.*)$ /article.php?id=$1&slug=$2 last;

    # Redirecionar páginas antigas
    location /about-us {
        return 301 /sobre;
    }

    location /category {
        rewrite ^/category/(.*)$ /categoria/$1 permanent;
    }

    # Bloquear hotlinking
    location ~ \.(jpg|jpeg|png|gif)$ {
        valid_referers none blocked site.com *.site.com;
        if ($invalid_referer) {
            return 403;
        }
    }

    # Forçar download de certos arquivos
    location ~ \.(pdf|doc)$ {
        add_header Content-Disposition "attachment";
    }
}

Rate Limiting

limit_req_zone e limit_req

# No bloco http (nginx.conf)
# Define a zona de rate limiting
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=100r/s;

# Também pode usar $server_name como chave
limit_req_zone $server_name zone=site_limit:10m rate=1000r/s;

# Rate por URI
limit_req_zone $binary_remote_addr$uri zone=uri_limit:10m rate=10r/s;
server {
    # Aplicar rate limiting global
    location / {
        limit_req zone=general_limit burst=200 nodelay;
    }

    # Rate limit restrito para API
    location /api/ {
        limit_req zone=api_limit burst=50 nodelay;
        proxy_pass http://api_backend;
    }

    # Rate limit severo para login
    location /login {
        limit_req zone=login_limit burst=3;
        limit_req_status 429;
        proxy_pass http://auth_backend;
    }

    # Rate limit por URI
    location /search {
        limit_req zone=uri_limit burst=10 nodelay;
        proxy_pass http://search_backend;
    }
}

Burst e Nodelay

# Sem burst: excesso é rejeitado imediatamente
location /api/ {
    limit_req zone=api_limit;
}

# Com burst: permite picos acima da taxa
# 30 req/s com burst=20 permite até 50 req/s por curto período
location /api/ {
    limit_req zone=api_limit burst=20;
}

# Com burst e nodelay: processa o burst imediatamente
# em vez de enfileirar
location /api/ {
    limit_req zone=api_limit burst=20 nodelay;
}

# Status personalizado para rate limit
location /api/ {
    limit_req zone=api_limit burst=20 nodelay;
    limit_req_status 429;
    # Retorna header informativo
    add_header Retry-After 5 always;
}

limit_conn_zone (Conexões Simultâneas)

# No bloco http
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $server_name zone=server:10m;

server {
    # Limitar conexões por IP
    location /downloads/ {
        limit_conn addr 2;
        limit_conn_status 503;
    }

    # Limitar conexões por servidor
    location / {
        limit_conn server 100;
    }

    # Limitar conexões por IP + nível de zona adicional
    location /stream/ {
        limit_conn addr 1;
        limit_conn_log_level warn;
    }
}

Geo, Allow e Deny

Bloqueio por Geolocalização

# No bloco http - baixar banco GeoIP
# sudo apt install libnginx-mod-http-geoip

geoip_country /usr/share/GeoIP/GeoIP.dat;

server {
    location / {
        # Bloquear países específicos
        if ($geoip_country_code ~ (CN|RU|KP)) {
            return 403;
        }
    }
}

Allow e Deny por IP

location /admin {
    # Restringir acesso a IPs internos
    allow 127.0.0.1;
    allow 10.0.0.0/8;
    allow 192.168.0.0/16;
    deny all;
}

location /internal-api {
    allow 10.0.0.0/8;
    allow 172.16.0.0/12;
    deny all;
}

location /status {
    stub_status on;
    access_log off;
    allow 127.0.0.1;
    deny all;
}

Mapa geo para Regras Condicionais

# No bloco http
geo $blocked_country {
    default 0;
    CN 1;
    RU 1;
    KP 1;
    IR 1;
}

geo $is_internal {
    default 0;
    10.0.0.0/8 1;
    172.16.0.0/12 1;
    192.168.0.0/16 1;
    127.0.0.0/8 1;
}

server {
    location / {
        if ($blocked_country) {
            return 403;
        }
    }

    location /admin {
        if ($is_internal) {
            proxy_pass http://admin_backend;
        }
        return 403;
    }
}

Lab: Proteção contra Abuso com Rate Limiting

Configure proteção completa contra abuso usando rate limiting, restrição de IP e redirecionamentos.

# 1. Criar aplicação de teste
sudo mkdir -p /var/www/rate-limited
cat << 'HTML' | sudo tee /var/www/rate-limited/index.html
<!DOCTYPE html>
<html>
<head><title>Protegido</title></head>
<body>
    <h1>Site Protegido</h1>
    <ul>
        <li><a href="/api/">API (30 req/s)</a></li>
        <li><a href="/login">Login (5 req/min)</a></li>
        <li><a href="/downloads/">Downloads (2 conexões/IP)</a></li>
        <li><a href="/admin">Admin (IP interno)</a></li>
    </ul>
</body>
</html>
HTML

# 2. Criar configuração com rate limiting
cat << 'NGINX' | sudo tee /etc/nginx/sites-available/rate-limited-site
limit_req_zone $binary_remote_addr zone=general:10m rate=50r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=download:10m;

server {
    listen 80;
    server_name rate-limited.local;

    root /var/www/rate-limited;
    index index.html;

    # Rate limit geral
    location / {
        limit_req zone=general burst=100 nodelay;
        try_files $uri $uri/ =404;
    }

    # API com rate limit médio
    location /api/ {
        limit_req zone=api burst=50 nodelay;
        limit_req_status 429;
        add_header Retry-After 1 always;
        proxy_pass http://127.0.0.1:3000;
    }

    # Login com rate limit severo
    location /login {
        limit_req zone=login burst=3;
        limit_req_status 429;
        add_header Retry-After 60 always;
        proxy_pass http://127.0.0.1:3000;
    }

    # Downloads com limite de conexões simultâneas
    location /downloads/ {
        limit_conn download 2;
        limit_conn_status 503;
        alias /var/www/rate-limited/downloads/;
        autoindex on;
    }

    # Admin apenas para IPs internos
    location /admin {
        allow 127.0.0.1;
        allow 192.168.0.0/16;
        deny all;
    }

    # Redirecionamentos
    location /old-page {
        return 301 /new-page;
    }

    location ~ ^/product/([0-9]+)$ {
        return 301 /item?id=$1;
    }

    access_log /var/log/nginx/rate-limited-access.log;
    error_log /var/log/nginx/rate-limited-error.log;
}
NGINX

# 3. Habilitar e aplicar
sudo ln -sf /etc/nginx/sites-available/rate-limited-site /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

# 4. Testar rate limiting
echo "Testando requisições normais..."
curl -s -o /dev/null -w "%{http_code}" http://rate-limited.local/

echo -e "\n\nTestando rate limit (muitas requisições)..."
for i in {1..60}; do
    curl -s -o /dev/null -w "%{http_code} " http://rate-limited.local/api/ &
done
wait

echo -e "\n\nTestando restrição de IP..."
curl -s -o /dev/null -w "%{http_code}" http://rate-limited.local/admin/

echo -e "\n\nTestando redirect..."
curl -I http://rate-limited.local/old-page 2>&1 | grep Location

Rate limiting é sua primeira linha de defesa contra abuso. Use combinado com allow/deny, geo blocking e redirects. Sempre defina bursts adequados para não impactar usuários legítimos e use nodelay para evitar filas desnecessárias.