Nginx: guia completo de instalação, configuração e otimização para ambientes de alta demanda

Guia prático do NGINX: proxy reverso, balanceamento de carga, SSL/TLS, cache, rate limiting e configurações reais para ambientes de alta demanda.

Sumário

Em 2004, os servidores web líderes de mercado — Apache em especial — tinham um problema estrutural que ficou famoso como o “C10K problem”: lidar com dez mil conexões simultâneas de forma eficiente. A maioria dos servidores criava um processo ou thread separado para cada conexão, o que funcionava razoavelmente bem com centenas de usuários simultâneos, mas começava a colapsar quando a escala chegava a milhares.

Igor Sysoev, engenheiro de software russo que trabalhava como administrador de sistemas, enfrentava esse problema diariamente. Em 2002, começou a desenvolver em paralelo um servidor web com uma premissa arquitetural radicalmente diferente: em vez de um processo por conexão, um modelo baseado em eventos e operações não-bloqueantes que permitia um único processo gerenciar milhares de conexões simultâneas com overhead mínimo.

Dois anos depois, em outubro de 2004, lançou o NGINX. Hoje o NGINX roda em mais de 30% de todos os sites ativos na internet — do pequeno blog hospedado em VPS até a infraestrutura da Netflix, Airbnb e Dropbox. Neste guia você vai entender como esse servidor funciona por dentro, como instalá-lo e configurá-lo em Ubuntu, CentOS e Windows, como configurar proxy reverso com balanceamento de carga, SSL/TLS, cache, compressão e proteção contra ataques DDoS. Cada seção traz configurações reais, não apenas teoria.

A arquitetura que torna o NGINX diferente

Compreender por que o NGINX resolve o problema de alta concorrência melhor que o Apache tradicional exige entender os dois modelos arquiteturais em jogo.

O Apache clássico usa o modelo prefork ou worker: para cada requisição, ele aloca um processo ou thread dedicado. Com 1.000 usuários simultâneos, o servidor mantém 1.000 processos ativos. Com 10.000, 10.000 processos — consumindo memória proporcional e gerando overhead massivo de troca de contexto pelo sistema operacional.

O NGINX usa um modelo de evento não-bloqueante: um número pequeno de worker processes (tipicamente igual ao número de núcleos de CPU do servidor) gerencia todas as conexões usando multiplexação de I/O. Quando uma conexão aguarda dados da rede ou do disco, o worker process não fica bloqueado esperando — ele passa para atender outra conexão e retorna quando os dados estiverem disponíveis.

💡 Dica: A consequência prática desse modelo é que o NGINX consome uma fração do consumo de memória do Apache para o mesmo volume de conexões simultâneas. Em benchmarks de alta concorrência, NGINX mantém throughput estável onde o Apache começa a degradar por esgotamento de recursos.

Além de servidor web, o NGINX funciona simultaneamente como:

  • Proxy reverso: intermediário entre clientes e servidores backend, ocultando a infraestrutura interna
  • Balanceador de carga: distribui requisições entre múltiplos servidores backend com diferentes algoritmos
  • Cache HTTP: armazena respostas de servidores backend para servir requisições subsequentes sem tocar o backend
  • Proxy de email: suporta protocolos IMAP, POP3 e SMTP para infraestruturas de email

Instalação passo a passo

Ubuntu e Debian

# Atualize os índices de pacotes
sudo apt update

# Instale o NGINX
sudo apt install nginx

# Verifique o status do serviço
sudo systemctl status nginx

# Inicie o serviço (se não iniciou automaticamente)
sudo systemctl start nginx

# Habilite início automático com o sistema
sudo systemctl enable nginx

# Teste abrindo http://localhost — você verá a página de boas-vindas do NGINX

CentOS e RHEL

# Adicione o repositório EPEL
sudo yum install epel-release

# Instale o NGINX
sudo yum install nginx

# Verifique o status
sudo systemctl status nginx

# Inicie e habilite o serviço
sudo systemctl start nginx
sudo systemctl enable nginx

# Configure o firewall para permitir tráfego HTTP e HTTPS
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

Windows

No Windows, o NGINX opera como processo de linha de comando sem integração com o gerenciador de serviços do sistema:

# Baixe o pacote ZIP do site oficial (nginx.org/en/download.html)
# Extraia para C:\nginx
# Abra o Prompt de Comando como Administrador e navegue até o diretório
cd C:\nginx

# Inicie o NGINX
nginx.exe

# Recarregue a configuração sem parar o servidor
nginx.exe -s reload

# Pare o NGINX graciosamente (aguarda conexões ativas terminarem)
nginx.exe -s quit

# Pare o NGINX imediatamente
nginx.exe -s stop

⚠️ Atenção: O suporte ao Windows é funcional mas limitado — o modelo de eventos do NGINX no Windows usa select() em vez dos mecanismos mais eficientes disponíveis no Linux (epoll) e macOS (kqueue). Para produção, hosts Linux oferecem performance significativamente superior.

Configurações básicas pós-instalação

Após a instalação, verifique e ajuste a estrutura de diretórios principal:

/etc/nginx/                → diretório raiz de configurações

/etc/nginx/nginx.conf      → arquivo de configuração principal

/etc/nginx/conf.d/         → configurações adicionais incluídas pelo nginx.conf

/var/www/html/             → diretório padrão para conteúdo web

/var/log/nginx/access.log  → log de todas as requisições HTTP

/var/log/nginx/error.log   → log de erros e advertências

Verifique os logs imediatamente após a instalação para confirmar que o serviço iniciou sem erros:

sudo tail -f /var/log/nginx/error.log

O arquivo nginx.conf: entendendo cada bloco

O arquivo de configuração principal do NGINX usa uma estrutura hierárquica de blocos que determina o escopo de cada diretiva:

# Contexto global — se aplica ao processo NGINX inteiro

user www-data;

worker_processes auto;   # 'auto' usa um worker por núcleo de CPU

pid /run/nginx.pid;

events {
    worker_connections 1024;   # Conexões máximas por worker process
    multi_accept on;           # Cada worker aceita múltiplas conexões por vez
}

http {

    # Configurações que se aplicam a todo tráfego HTTP
    sendfile on;          # Envio eficiente de arquivos via syscall do kernel
    tcp_nopush on;        # Otimiza envio de headers junto com início dos dados
    tcp_nodelay on;       # Reduz latência em conexões keep-alive
    keepalive_timeout 65; # Mantém conexões abertas por 65 segundos
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    gzip on;   # Compressão de respostas — detalhado mais adiante
    include /etc/nginx/conf.d/*.conf;   # Inclui configurações de sites individuais
}

Crie um arquivo separado em /etc/nginx/conf.d/meusite.conf para cada site ou aplicação que o NGINX serve — isso mantém a configuração organizada e facilita habilitar ou desabilitar sites individualmente:

server {
    listen 80;
    server_name meusite.com www.meusite.com;
    root /var/www/meusite;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

Após qualquer modificação de configuração, verifique a sintaxe antes de reiniciar:

sudo nginx -t         # Testa a configuração
sudo systemctl reload nginx   # Recarrega sem interromper conexões ativas

Proxy reverso: redirecionando tráfego para servidores backend

O proxy reverso é provavelmente o uso mais comum do NGINX em produção. Em vez de expor diretamente o servidor de aplicação (Node.js, Django, Rails, Spring Boot) à internet, o NGINX recebe todas as requisições externas e as repassa para o backend internamente.

Configuração básica de proxy reverso

server {
    listen 80;
    server_name meusite.com;
    location / {
        proxy_pass http://localhost:3000;   # Backend Node.js rodando localmente

        # Headers essenciais para o backend receber informações corretas do cliente
        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;

        # Suporte a WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
    }
}

O header X-Real-IP passa o endereço IP real do cliente para o backend — sem ele, o backend veria o IP do NGINX como origem de todas as requisições, o que quebra qualquer lógica de rate limiting ou geolocalização no nível da aplicação.

NGINX como proxy para frameworks específicos

Django com Gunicorn:

server {
    listen 80;
    server_name meusite.com;
    location / {
        proxy_pass http://unix:/var/run/gunicorn.sock;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Arquivos estáticos servidos diretamente pelo NGINX (muito mais eficiente)
    location /static/ {
        alias /var/www/meusite/staticfiles/;
    }
}

PHP com PHP-FPM:

server {
    listen 80;
    server_name meusite.com;
    root /var/www/meusite;
    index index.php index.html;
    location / {
        try_files $uri $uri/ =404;
    }

    # Processa arquivos PHP via FastCGI
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    }

    # Bloqueia acesso a arquivos .htaccess (específicos do Apache)
    location ~ /\.ht {
        deny all;
    }
}

Balanceamento de carga entre múltiplos servidores

O NGINX distribui tráfego entre múltiplos servidores backend usando o bloco upstream. Três algoritmos principais cobrem a maioria dos casos de uso:

Round-robin (padrão): distribuição equitativa

upstream backend {
    server backend1.exemplo.com;
    server backend2.exemplo.com;
    server backend3.exemplo.com;
}

server {
    listen 80;
    server_name meusite.com;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Least connections: direciona para o servidor menos sobrecarregado

upstream backend {
    least_conn;
    server backend1.exemplo.com;
    server backend2.exemplo.com;
    server backend3.exemplo.com;
}

Mais eficiente que round-robin quando requisições têm tempo de processamento variável — servidores rápidos recebem mais tráfego automaticamente.

IP hash: garante que o mesmo cliente sempre vai para o mesmo servidor

upstream backend {
    ip_hash;
    server backend1.exemplo.com;
    server backend2.exemplo.com;
}

Útil para aplicações que mantêm sessão de usuário no servidor — sem IP hash, o mesmo usuário pode cair em servidores diferentes a cada requisição, perdendo o estado de sessão.

💡 Dica: Adicione pesos quando os servidores têm capacidades diferentes (server backend1.exemplo.com weight=3;), e use a diretiva backup para servidores de failover que só recebem tráfego quando todos os primários estão fora: server backup.exemplo.com backup;.

SSL/TLS: configurando HTTPS corretamente

HTTPS não é opcional em 2025 — navegadores marcam sites HTTP como inseguros, e o Google usa HTTPS como sinal de ranqueamento. Esta configuração cobre todos os requisitos de um servidor HTTPS moderno:

# Redireciona todo tráfego HTTP para HTTPS
server {
    listen 80;
    server_name meusite.com www.meusite.com;
    return 301 https://$host$request_uri;
}

# Bloco HTTPS principal
server {
    listen 443 ssl http2;
    server_name meusite.com www.meusite.com;

    # Caminhos para o certificado e chave privada
    ssl_certificate /etc/nginx/ssl/meusite.crt;
    ssl_certificate_key /etc/nginx/ssl/meusite.key;

    # Apenas versões seguras do TLS
    ssl_protocols TLSv1.2 TLSv1.3;

    # Ciphers modernos e seguros
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # Cache de sessão SSL — melhora performance em conexões repetidas
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # HSTS — instrui navegadores a só usarem HTTPS por 1 ano
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # Cabeçalhos de segurança adicionais
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    root /var/www/meusite;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

⚠️ Atenção: Nunca use SSL v3, TLS 1.0 ou TLS 1.1 — esses protocolos têm vulnerabilidades conhecidas e exploráveis (POODLE, BEAST). TLS 1.2 com ciphers modernos e TLS 1.3 são os únicos protocolos aceitáveis para produção. Ferramentas como SSL Labs (ssllabs.com/ssltest/) verificam a qualidade da sua configuração SSL gratuitamente.

Para usar certificados gratuitos do Let’s Encrypt, instale o Certbot que configura e renova automaticamente:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d meusite.com -d www.meusite.com

# O Certbot modifica automaticamente o nginx.conf e configura renovação automática

Cache: reduzindo carga no backend e latência para o usuário

Configuração de cache de proxy

http {

    # Define onde o cache fica e seu tamanho máximo
    proxy_cache_path /var/cache/nginx
                     levels=1:2
                     keys_zone=meu_cache:10m
                     max_size=10g
                     inactive=60m
                     use_temp_path=off;
    server {
        listen 80;
        server_name meusite.com;
        location / {
            proxy_cache meu_cache;
            proxy_pass http://backend_server;

            # Tempo de validade do cache por código de resposta
            proxy_cache_valid 200 1h;     # Cache respostas 200 por 1 hora
            proxy_cache_valid 301 24h;    # Cache redirecionamentos por 24 horas
            proxy_cache_valid any 1m;     # Qualquer outro código por 1 minuto

            # Adiciona header mostrando se a resposta veio do cache
            add_header X-Cache-Status $upstream_cache_status;

            # Não faz cache quando o cliente envia esses headers
            proxy_cache_bypass $http_pragma $http_authorization;
        }
    }
}

O header X-Cache-Status que você adiciona aceita os valores HIT (respondido do cache), MISS (foi ao backend), BYPASS (ignorou o cache) e EXPIRED (cache expirado, foi ao backend). Use esse header para verificar se o cache está funcionando corretamente.

Cache de conteúdo estático com Expires

Para arquivos estáticos que raramente mudam, configure um tempo de cache longo diretamente nos headers da resposta:

location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
    expires 30d;                                    # Navegador caches por 30 dias
    add_header Cache-Control "public, no-transform";
}

Compressão gzip: reduzindo o tamanho das respostas

Compressão gzip reduz o tamanho de transferência de arquivos de texto (HTML, CSS, JavaScript, JSON) em 60-80%, acelerando carregamento de páginas e reduzindo consumo de banda:

http {
    gzip on;
    gzip_comp_level 5;          # Nível 1-9; 5 equilibra compressão e CPU
    gzip_min_length 256;        # Não comprime respostas menores que 256 bytes
    gzip_vary on;               # Adiciona header Vary para proxies intermediários
    gzip_proxied any;           # Comprime também respostas de proxies upstream
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
}

Não ative gzip para imagens JPEG, PNG ou outros formatos binários — esses formatos já são comprimidos e tentar comprimir novamente desperdiça CPU sem reduzir o tamanho.

Segurança: proteção contra DDoS e ataques comuns

Rate limiting: limitando requisições por IP

http {
    # Define zona de limite: 10MB para armazenar estado por IP
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s;

    server {
        # Limite geral: 10 requisições/segundo com burst de 20
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
            proxy_pass http://backend;
        }

        # Limite mais restrito para endpoint de login
        location /login {
            limit_req zone=login_limit burst=5;
            proxy_pass http://backend
        }
    }
}

Limitando conexões simultâneas por IP

http {
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    server {
        location / {
            limit_conn conn_limit 10;    # Máximo 10 conexões simultâneas por IP
            proxy_pass http://backend;
        }
    }
}

Bloqueando métodos HTTP não utilizados

server {
    # Aceita apenas GET, POST e HEAD; retorna 405 para qualquer outro
    if ($request_method !~ ^(GET|POST|HEAD)$) {
        return 405;
    }
}

Protegendo arquivos e diretórios sensíveis

# Bloqueia acesso a arquivos de configuração e ocultos
location ~ /\.(ht|git|env) {
    deny all;
}

# Bloqueia acesso a arquivos de backup
location ~ \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)$ {
    deny all;
}

Otimização de performance: configurações que fazem diferença

Keep-alive e configurações de conexão

http {
    keepalive_timeout 65;      # Mantém conexão aberta por 65 segundos
    keepalive_requests 100;    # Máximo de requisições por conexão keep-alive
    sendfile on;               # Usa syscall sendfile() do kernel — mais eficiente
    tcp_nopush on;             # Agrupa headers de resposta em um único pacote
    tcp_nodelay on;            # Desativa algoritmo Nagle para conexões keep-alive

    # Buffers de requisição e resposta
    client_body_buffer_size 16k;
    client_max_body_size 8m;         # Tamanho máximo de upload
    client_header_buffer_size 1k;
    large_client_header_buffers 4 16k;

    # Timeouts
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;
}

Ajuste de worker processes e conexões

# Worker processes: 'auto' usa um por núcleo de CPU — ideal para a maioria dos casos
worker_processes auto;

# Para servidores com muitos arquivos estáticos, ajuste o limite de arquivos abertos
worker_rlimit_nofile 65535;
events {
    worker_connections 4096;   # Conexões simultâneas por worker process
    multi_accept on;           # Cada worker aceita múltiplas conexões por iteração
    use epoll;                 # Mecanismo de I/O mais eficiente no Linux
}

Monitoramento e diagnóstico

Habilitando o módulo de status

server {
    listen 80;
    server_name localhost;
    location /nginx_status {
        stub_status on;
        allow 127.0.0.1;    # Acesso apenas de localhost
        deny all;
    }
}

Acesse http://localhost/nginx_status para ver conexões ativas, requisições por segundo e outros indicadores básicos de saúde do servidor.

Ferramentas de monitoramento externas

NGINX Amplify (saas.amplify.nginx.com) oferece monitoramento detalhado específico para NGINX com dashboards, alertas e análise de configuração. A versão básica é gratuita para um servidor.

Prometheus + Grafana com o exporter nginx-prometheus-exporter expõe métricas do NGINX no formato Prometheus, permitindo criar dashboards personalizados e alertas baseados em thresholds específicos — adequado para times que já usam esse stack de observabilidade.

Perguntas frequentes sobre NGINX

Qual a diferença entre NGINX e Apache? Quando escolher cada um?


O Apache usa modelo de processo/thread por conexão, o que o torna mais flexível para módulos e configuração por diretório via .htaccess, mas menos eficiente em alta concorrência. O NGINX usa modelo de eventos não-bloqueante que escala muito melhor para muitas conexões simultâneas com uso menor de memória. Na prática: prefira NGINX para servir conteúdo estático em alta escala, proxy reverso e balanceamento de carga. Prefira Apache quando você precisa de módulos específicos do Apache (como mod_rewrite em configurações complexas de .htaccess) ou para aplicações PHP legadas que assumem Apache. Muitas arquiteturas usam os dois juntos: NGINX na frente como proxy reverso e Apache atrás para executar PHP.

Como recarregar a configuração do NGINX sem interromper conexões ativas?


Use sudo nginx -t para verificar a sintaxe da configuração nova. Se o teste passar, execute sudo systemctl reload nginx (ou sudo nginx -s reload). Esse comando instrui o NGINX a recarregar a configuração graciosamente — o master process cria novos worker processes com a configuração atualizada e aguarda os worker processes antigos terminarem as conexões em andamento antes de encerrá-los. O tráfego em curso nunca é interrompido.

O NGINX pode substituir completamente um servidor de aplicação como Gunicorn ou Unicorn?


Não — são ferramentas para propósitos distintos. Gunicorn, Unicorn, uWSGI e similares executam código de aplicação (Python, Ruby, etc.). O NGINX não executa código de aplicação; ele recebe conexões HTTP, as encaminha para o servidor de aplicação via proxy, e serve o resultado. A combinação padrão é NGINX na frente (recebendo conexões da internet, servindo arquivos estáticos, fazendo SSL termination) com o servidor de aplicação atrás (executando a lógica de negócio).

Como configurar o NGINX para funcionar com Docker?


O caso mais comum é usar a imagem oficial nginx:alpine como container que serve conteúdo estático ou como proxy reverso para outros containers. Em um docker-compose.yml, o NGINX recebe conexões externas na porta 80/443 e encaminha para containers de aplicação na rede interna do Docker. Use volumes para montar o arquivo nginx.conf e os certificados SSL no container, e a diretiva proxy_pass http://nome-do-servico:porta para encaminhar tráfego para outros containers usando os nomes de serviço como hostname na rede Docker.

Como saber se o cache do NGINX está funcionando?


Adicione o header add_header X-Cache-Status $upstream_cache_status; na configuração. Faça uma requisição e inspecione os headers da resposta — X-Cache-Status: MISS indica que o NGINX foi ao backend; X-Cache-Status: HIT indica que serviu do cache. A primeira requisição para uma URL sempre gera MISS; a segunda deve gerar HIT se o cache estiver configurado corretamente. Use curl -I https://meusite.com/recurso para inspecionar headers de resposta rapidamente sem abrir o navegador.

Conclusão

O NGINX resolveu um problema técnico real — como um servidor web com um único processo gerencia dez mil conexões simultâneas — e essa solução elegante se tornou a infraestrutura silenciosa de uma fração enorme da internet moderna. Entender a arquitetura orientada a eventos que o torna eficiente em alta concorrência explica tanto por que ele existe quanto onde ele se encaixa melhor.

Três pontos resumem o essencial deste guia. Primeiro, o NGINX raramente opera apenas como servidor web — sua força real emerge quando você o configura como proxy reverso com SSL termination na frente de servidores de aplicação, separando a responsabilidade de gerenciar conexões HTTP (onde NGINX é excelente) da responsabilidade de executar lógica de aplicação (onde Gunicorn, Node.js ou Spring Boot são mais adequados). Segundo, configurações de segurança como rate limiting, limitação de conexões por IP e bloqueio de métodos HTTP não utilizados devem ser implementadas desde o início, não depois de um incidente. Terceiro, verificar sempre a configuração com nginx -t antes de aplicar mudanças e usar reload em vez de restart são hábitos que evitam interrupções desnecessárias em produção.

O arquivo de configuração do NGINX parece intimidador até você entender que ele é composto por blocos hierárquicos com semântica clara. Depois disso, configurar proxy reverso, balanceamento de carga e HTTPS se torna um processo direto — e você passa a entender por que tantas equipes confiam nessa ferramenta criada por um administrador de sistemas frustrado com servidores lentos em 2002.

Se este guia ajudou você a configurar o NGINX com mais confiança, compartilhe com o time de infraestrutura. Configuração correta desde o início economiza muito mais tempo do que debug de problemas de performance em produção.

Uma resposta

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *