Nginx na VPS: configuração básica e proxy reverso

Nginx é o servidor web e proxy reverso mais usado em VPS, recebe todo o tráfego nas portas 80 e 443 e direciona para os apps corretos por domínio ou caminho. Com ele você hospeda múltiplos apps na mesma VPS (cada um num subdomínio), adiciona HTTPS e compressão sem alterar o código dos apps.

Instalar o Nginx com Docker

A forma mais prática de rodar Nginx em VPS com Docker é como container, com a configuração montada como volume:

yaml
# docker-compose.yml para Nginx como proxy reverso
services:
  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
      - certbot_conf:/etc/letsencrypt:ro
      - certbot_www:/var/www/certbot
    networks:
      - proxy

networks:
  proxy:
    name: nginx_proxy   # rede compartilhada com os apps

Proxy reverso: configuração por subdomínio

Crie um arquivo de configuração para cada app no diretório conf.d. Cada arquivo define um bloco server para um domínio:

nginx
# nginx/conf.d/n8n.conf
server {
    listen 80;
    server_name n8n.seudominio.com.br;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name n8n.seudominio.com.br;

    ssl_certificate     /etc/letsencrypt/live/n8n.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/n8n.seudominio.com.br/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;

    # WebSocket — necessário para n8n, Chatwoot, etc.
    location / {
        proxy_pass http://n8n:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_read_timeout 300s;
    }
}

Múltiplos apps na mesma VPS

Cada app tem seu arquivo .conf com um server_name diferente. O Nginx roteia pelo Host header:

nginx
# nginx/conf.d/chatwoot.conf
server {
    listen 443 ssl;
    http2 on;
    server_name chat.seudominio.com.br;

    ssl_certificate     /etc/letsencrypt/live/chat.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.seudominio.com.br/privkey.pem;

    client_max_body_size 50M;   # para upload de anexos

    location / {
        proxy_pass http://chatwoot_rails:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /cable {
        proxy_pass http://chatwoot_rails:3000/cable;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Performance: gzip e cache de estáticos

Adicione ao nginx.conf principal (ou a um arquivo incluído) para melhorar a performance de todos os apps:

nginx
# nginx/conf.d/performance.conf
# Gzip para reduzir tamanho das respostas
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types
    text/plain text/css text/xml application/json
    application/javascript application/xml+rss
    application/atom+xml image/svg+xml
    font/woff font/woff2;

# Cache agressivo para assets estáticos
map $sent_http_content_type $expires {
    default                    off;
    text/html                  epoch;
    text/css                   1y;
    application/javascript     1y;
    ~image/                    1y;
    font/woff2                 1y;
}
expires $expires;

# Limitar tamanho do buffer de proxy (evita erro 502)
proxy_buffer_size          128k;
proxy_buffers              4 256k;
proxy_busy_buffers_size    256k;

Recarregar e testar a configuração

Sempre teste a configuração antes de recarregar para evitar downtime:

bash
# Testar sintaxe sem aplicar (dentro do container)
docker compose exec nginx nginx -t

# Se OK, recarregar sem downtime
docker compose exec nginx nginx -s reload

# Ver logs de erro em tempo real
docker compose logs nginx -f

# Testar um virtual host específico
curl -I https://n8n.seudominio.com.br

# Ver qual server_name está respondendo
curl -v https://n8n.seudominio.com.br 2>&1 | grep -E "Server:|< HTTP"

# Verificar headers de segurança
curl -I https://seudominio.com.br | grep -E "Strict|X-Frame|Content-Security"

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Nginx em Docker é mais portável e isolado, a configuração vai junto com o projeto em arquivos de texto. Nginx no host tem acesso direto ao sistema de arquivos e é marginalmente mais rápido (sem overhead de rede Docker). Para VPS com múltiplos apps em Docker, Nginx em container (ou Nginx Proxy Manager) é mais prático. Para apps com muitos assets estáticos, Nginx no host serve arquivos mais eficientemente.

Servidor web: Nginx serve arquivos estáticos diretamente (HTML, CSS, JS, imagens). Proxy reverso: Nginx recebe a requisição e repassa para outro serviço (Node.js, Python, Docker container). Para apps modernas em Docker, Nginx funciona como proxy reverso, os arquivos estáticos são servidos pelo app ou por CDN.

502 significa que o Nginx conseguiu conectar mas o serviço upstream (seu app) não respondeu. Causas: container do app parado (docker ps); app travado (docker logs); timeout, aumente proxy_read_timeout; container do app em rede diferente do Nginx (docker network ls). Erro 504 é similar mas é timeout na conexão ao upstream.

No bloco http (ou num arquivo include): limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;, cria zona de 10 MB que permite 10 req/s por IP. No location: limit_req zone=api burst=20 nodelay;, permite burst de 20 req e rejeita excesso imediatamente. Retorna 429 (Too Many Requests) para clientes que excedem o limite.

Sim, especialmente para iniciantes ou quando você gerencia 5+ apps. NPM tem interface web para configurar proxy hosts, SSL automático e redirects sem editar arquivos de configuração. A desvantagem é menor controle granular e ~200 MB de RAM extra. Para configurações avançadas (rate limiting, headers customizados, auth), Nginx manual dá mais controle.