Guides
Fundamentos ▾
Versionamento ▾
Deploy ▾

Nginx

Servidor web de alta performance. Reverse proxy, load balancer, cache, SSL termination.

Arquitetura

1
Client
request HTTP/S
2
Nginx
worker process
3
Backend
Node, Python, PHP
ComponenteFunção
master processgerencia workers (root)
worker processprocessa conexões (www-data)
epoll/kqueueevent loop de alta performance

Estrutura de arquivos

/etc/nginx/
├── nginx.conf              # config principal
├── sites-available/        # configs de virtual hosts
├── sites-enabled/          # symlinks para ativar
├── conf.d/                 # configs extras (*.conf)
├── mime.types              # tipos de MIME
└── fastcgi_params          # parâmetros FastCGI

Instalação e Gerenciamento

# instalar
sudo apt update && sudo apt install nginx -y

# status
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl reload nginx    # reload configs (zero downtime)
sudo systemctl restart nginx   # restart (dropa conexões)

# habilitar na inicialização
sudo systemctl enable nginx

# testar configuração
sudo nginx -t
sudo nginx -T    # testar + mostrar config completa

# logs
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
    use epoll;
}

http {
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    client_max_body_size 16M;

    include /etc/nginx/mime.types;

    gzip on;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json
               application/javascript text/xml image/svg+xml;

    limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Virtual Host (Server Block)

server {
    listen 80;
    listen [::]:80;
    server_name meu-site.com www.meu-site.com;

    root /var/www/meu-site;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

SPA (React, Vue, Angular)

server {
    listen 80;
    server_name meu-app.com;

    root /var/www/meu-app;
    index index.html;

    # SPA routing
    location / {
        try_files $uri $uri/ /index.html;
    }

    # cache de assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

Proxy Reverso

upstream backend {
    server 127.0.0.1:3000;
}

server {
    listen 80;
    server_name api.meu-app.com;

    location / {
        proxy_pass http://backend;
        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;
    }
}

PHP-FPM

location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Load Balancing

# round-robin (padrão)
upstream backend {
    server 10.0.0.1:3000;
    server 10.0.0.2:3000;
    server 10.0.0.3:3000 backup;
}

# ip_hash — mesmo client → mesmo server
upstream backend {
    ip_hash;
    server 10.0.0.1:3000;
    server 10.0.0.2:3000;
}

# least_conn — menos conexões ativas
upstream backend {
    least_conn;
    server 10.0.0.1:3000;
    server 10.0.0.2:3000;
}

# com pesos
upstream backend {
    server 10.0.0.1:3000 weight=3;
    server 10.0.0.2:3000 weight=1;
}

SSL / HTTPS

# certificado autoassinado (dev)
sudo openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/selfsigned.key \
  -out /etc/nginx/ssl/selfsigned.crt \
  -subj "/C=BR/ST=SP/L=SP/O=Dev/CN=localhost"

# config HTTPS
server {
    listen 443 ssl http2;
    server_name meu-site.com;

    ssl_certificate /etc/nginx/ssl/selfsigned.crt;
    ssl_certificate_key /etc/nginx/ssl/selfsigned.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    add_header Strict-Transport-Security
      "max-age=63072000; includeSubDomains" always;
}

# HTTP → HTTPS redirect
server {
    listen 80;
    server_name meu-site.com;
    return 301 https://$host$request_uri;
}

Let's Encrypt (Certbot)

sudo apt install certbot python3-certbot-nginx -y

# plugin nginx configura automaticamente
sudo certbot --nginx -d meu-site.com -d www.meu-site.com

# standalone (sem nginx rodando)
sudo certbot certonly --standalone -d meu-site.com

# DNS challenge (wildcard)
sudo certbot certonly --manual --preferred-challenges dns \
  -d "*.meu-site.com" -d "meu-site.com"

# renovação automática
sudo certbot renew --dry-run

# cron de renovação
echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload nginx'" | \
  sudo tee /etc/cron.d/certbot-renew

Certificados ficam em /etc/letsencrypt/live/meu-site.com/

Cache

# proxy cache
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;

location /api/ {
    proxy_pass http://backend;
    proxy_cache my_cache;
    proxy_cache_valid 200 302 10m;
    add_header X-Cache-Status $upstream_cache_status;
}

# assets com hash (Vite, Webpack)
location ~* \.(js|css)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

# HTML (não cachear)
location ~* \.html$ {
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}

Rate Limiting

# no bloco http
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    location /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 /download/ {
        limit_conn addr 5;
    }

    limit_req_status 429;
}

Gzip e Brotli

# Gzip
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/javascript
           text/xml image/svg+xml;

# Brotli (se compilado)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript
             image/svg+xml;

Segurança

server {
    server_tokens off;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'" always;

    # bloquear arquivos sensíveis
    location ~ /\. { deny all; }
    location ~* \.(env|ini|log|bak|sql)$ { deny all; }

    # rate limiting
    limit_req zone=general burst=20 nodelay;
}

Logs

# formato customizado
log_format main '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '$request_time $upstream_response_time';

# formato JSON (para ELK/Loki)
log_format json escape=json '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"status":$status,'
    '"request_time":$request_time'
'}';

access_log /var/log/nginx/meu-site.access.log main;
access_log /var/log/nginx/meu-site.access.log json;

Proxy WebSocket

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_read_timeout 86400s;
}

Monitoramento

# stub_status
server {
    listen 127.0.0.1:8080;
    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}

# testar
curl http://127.0.0.1:8080/nginx_status

Referência Rápida

SituaçãoConfiguração
SPA routingtry_files $uri $uri/ /index.html
Redirect HTTP→HTTPSreturn 301 https://$host$request_uri
Proxy reversoproxy_pass http://backend
WebSocketproxy_set_header Upgrade $http_upgrade
Cache assetsexpires 1y; Cache-Control "public, immutable"
Rate limitinglimit_req zone=api burst=20 nodelay
Esconder versãoserver_tokens off
Gzipgzip on; gzip_types ...;
Log JSONlog_format json escape=json '{...}'
Certbotsudo certbot --nginx -d site.com
Testar configsudo nginx -t
Reloadsudo systemctl reload nginx