kb.erickguedes.com
Nginx: Performance e Proxy Reverso

Proxy Reverso e Load Balancing

Aula 2 de 6

Proxy Reverso com proxy_pass

Configuração Básica

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

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

proxy_set_header - Cabeçalhos Essenciais

location / {
    proxy_pass http://localhost:8080;

    # Cabeçalhos padrão de proxy
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;

    # Suprimir cabeçalhos indesejados
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

Proxy para Múltiplos Backends

# Proxy diferentes caminhos para diferentes backends
server {
    listen 80;
    server_name api.exemplo.com;

    location / {
        proxy_pass http://localhost:3000;
    }

    location /api/ {
        proxy_pass http://localhost:8080/api/;
    }

    location /admin/ {
        proxy_pass https://admin.internal:8443/;
        proxy_ssl_verify on;
        proxy_ssl_trusted_certificate /etc/nginx/ssl/internal-ca.crt;
    }

    location /static/ {
        root /var/www/public;
        expires 1y;
    }
}

Upstream e Load Balancing

Configuração de Upstream

upstream backend_cluster {
    # Método de balanceamento
    # round-robin (padrão), least_conn, ip_hash, random, hash

    # Servidores do cluster
    server backend1.exemplo.com:8080 weight=3;
    server backend2.exemplo.com:8080 weight=2;
    server backend3.exemplo.com:8080 weight=1 backup;

    # Health check (Nginx Plus)
    # zone backend 64k;
    # health_check interval=5 fails=3 passes=2;
}

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

    location / {
        proxy_pass http://backend_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Métodos de Balanceamento

# Round-Robin (padrão)
upstream backend {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

# Least Connections
upstream backend {
    least_conn;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

# IP Hash (sessões persistentes)
upstream backend {
    ip_hash;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

# Hash genérico (por query string, cookie, etc.)
upstream backend {
    hash $request_uri consistent;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

# Random (distribuição uniforme)
upstream backend {
    random two least_conn;
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

Flags de Servidor no Upstream

upstream backend {
    # Peso maior = mais requisições
    server 10.0.0.1:8080 weight=5;

    # Backup: só recebe requisições se os principais falharem
    server 10.0.0.2:8080 backup;

    # Down: marca como offline (sem remover do config)
    server 10.0.0.3:8080 down;

    # max_fails/fail_timeout: quantas falhas até marcar como down
    server 10.0.0.4:8080 max_fails=3 fail_timeout=30s;

    # Slow start (Nginx Plus): ramp up gradual
    server 10.0.0.5:8080 slow_start=30s;
}

Health Checks

Passive Health Checks (open source)

upstream backend {
    server 10.0.0.1:8080 max_fails=3 fail_timeout=30s;
    server 10.0.0.2:8080 max_fails=3 fail_timeout=30s;

    # Proxy timeouts para detectar falhas mais rápido
    proxy_connect_timeout 5s;
    proxy_read_timeout 10s;
    proxy_send_timeout 10s;
}

Active Health Checks (Nginx Plus)

upstream backend {
    zone backend 64k;

    server 10.0.0.1:8080;
    server 10.0.0.2:8080;

    health_check interval=5 fails=3 passes=2;
    health_check uri=/health;
    health_match expected 200;
}

Buffers e Timeouts

location / {
    proxy_pass http://backend;

    # Tamanho dos buffers
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
    proxy_busy_buffers_size 8k;

    # Desabilitar buffer para streaming
    proxy_buffering off;

    # Aumentar buffers para respostas grandes
    proxy_buffer_size 8k;
    proxy_buffers 16 8k;
    proxy_busy_buffers_size 16k;
    proxy_max_temp_file_size 0;

    # Timeouts
    proxy_connect_timeout 10s;      # Conexão com backend
    proxy_read_timeout 30s;         # Esperando resposta
    proxy_send_timeout 30s;         # Enviando requisição

    # Tamanho máximo do corpo
    client_max_body_size 100m;
    client_body_buffer_size 128k;
}

WebSocket Proxy

# Mapeamento para upgrade de conexão
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    serverName ws.exemplo.com;

    # Proxy HTTP normal
    location / {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Proxy WebSocket
    location /ws {
        proxy_pass http://ws_backend:8080;

        # Headers obrigatórios para WebSocket
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

        # Timeouts longos para WebSocket
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Lab: Cluster com Proxy Reverso

Configure um proxy reverso com balanceamento de carga para uma aplicação Node.js.

# 1. Criar aplicação Node.js de exemplo
sudo mkdir -p /opt/app
cat << 'APP' | sudo tee /opt/app/server.js
const http = require('http');
const os = require('os');
const port = process.env.PORT || 3000;

http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(`Servidor: ${os.hostname()} | Porta: ${port}\n`);
}).listen(port, () => {
    console.log(`Servidor rodando na porta ${port}`);
});
APP

# 2. Iniciar múltiplas instâncias
cd /opt/app
node server.js &
PORT=3001 node server.js &
PORT=3002 node server.js &

# 3. Criar configuração de upstream
cat << 'NGINX' | sudo tee /etc/nginx/sites-available/cluster
upstream app_cluster {
    least_conn;
    server 127.0.0.1:3000 max_fails=3 fail_timeout=10s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=10s;
    server 127.0.0.1:3002 max_fails=3 fail_timeout=10s;
}

server {
    listen 80;
    server_name cluster.local;

    location / {
        proxy_pass http://app_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_connect_timeout 5s;
        proxy_read_timeout 10s;
        proxy_buffering off;

        # Health check endpoint
        location /health {
            proxy_pass http://app_cluster;
            access_log off;
            return 200 "OK\n";
        }
    }

    # WebSocket support
    location /ws/ {
        proxy_pass http://app_cluster;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
    }

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

# 4. Habilitar e testar
sudo ln -sf /etc/nginx/sites-available/cluster /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default

# 5. Testar configuração
sudo nginx -t && sudo systemctl reload nginx

# 6. Testar balanceamento
for i in {1..6}; do
    curl -s http://cluster.local
done

# 7. Simular falha de um servidor
kill $(lsof -ti:3001)

# 8. Verificar se o health check removeu o servidor
for i in {1..3}; do
    curl -s http://cluster.local
done

Proxy reverso com Nginx vai além de redirecionar tráfego: ele adiciona resiliência com health checks, escalabilidade com load balancing, e performance com buffers e timeouts bem ajustados. Sempre configure cabeçalhos X-Forwarded-* para que o backend conheça o IP real do cliente.