Como configurar Nginx no Docker: volumes, HTTPS e proxy reverso

Pela sétima vez, você executa docker restart nginx e atualiza o navegador — mas a página de erro 502 continua lá. Você alterou o nginx.conf, porém a configuração dentro do contêiner simplesmente não muda.
Quase todo mundo que trabalha com contêineres já enfrentou problemas ao configurar Nginx no Docker. Montagem de arquivos, certificados HTTPS e comunicação entre contêineres parecem tarefas simples, mas escondem vários detalhes. Este artigo apresenta uma solução completa: da montagem correta dos arquivos de configuração à renovação automática de certificados HTTPS e à configuração de rede para o proxy reverso.
Você vai aprender:
- Por que as alterações na configuração não entram em vigor e cinco formas corretas de montar os arquivos
- O caminho completo para configurar certificados HTTPS, desde um certificado autoassinado até o Let’s Encrypt
- Como configurar a rede ao usar Nginx como proxy reverso para outros contêineres Docker
- Como reforçar a segurança e ajustar o desempenho em produção
Configuração básica e montagem de arquivos do Nginx no Docker
Por que montar os arquivos de configuração?
Talvez você esteja pensando: não dá para empacotar a configuração do Nginx diretamente na imagem? Dá, mas o custo operacional aparece rápido.
Cada pequena alteração exige reconstruir a imagem, enviá-la ao registro, baixá-la novamente e reiniciar o contêiner. Até concluir o processo, mais de dez minutos podem ter passado. Isso sem contar o versionamento da configuração e a troca entre ambientes. Se algo der errado em produção às duas da manhã, esperar uma nova imagem só para reverter uma configuração não é uma boa opção.
A montagem dos arquivos resolve esse problema: você altera o arquivo no host, e a mudança fica disponível dentro do contêiner. Testes, reversões e colaboração em equipe ficam bem mais simples.
Diretórios importantes no contêiner do Nginx
Primeiro, veja onde ficam os principais arquivos do Nginx dentro do contêiner:
/etc/nginx/
├── nginx.conf # Arquivo principal de configuração
├── conf.d/ # Configurações de cada site
│ └── default.conf # Configuração do site padrão
/usr/share/nginx/html # Raiz dos arquivos estáticos
/var/log/nginx/ # Diretório de logs
├── access.log
└── error.log
Há um detalhe importante: nginx.conf contém a linha include /etc/nginx/conf.d/*.conf;. Isso faz com que a configuração principal carregue automaticamente todos os arquivos .conf do diretório conf.d. Se você montar apenas nginx.conf e esquecer conf.d, a configuração dos sites não aparecerá no contêiner.
Como montar corretamente, passo a passo
Antes de iniciar o contêiner, prepare os arquivos. Esse cuidado evita vários problemas depois.
Etapa 1: copiar a configuração padrão do contêiner como modelo
Por que fazer isso? A configuração padrão oficial já foi testada. É mais seguro partir dela do que escrever tudo do zero.
# Inicie primeiro um contêiner temporário
docker run --name nginx-temp -d nginx
# Copie a configuração padrão
docker cp nginx-temp:/etc/nginx/nginx.conf ./nginx/nginx.conf
docker cp nginx-temp:/etc/nginx/conf.d ./nginx/conf.d
# Remova o contêiner quando terminar
docker stop nginx-temp && docker rm nginx-temp
Etapa 2: criar uma estrutura de diretórios padrão no host
Costumo manter todos os arquivos relacionados ao Docker em /opt, mas você pode ajustar o caminho conforme sua preferência:
mkdir -p /opt/nginx/{conf,conf.d,html,logs,ssl}
Essa estrutura cobre configurações, arquivos estáticos, logs e certificados SSL de uma vez.
Etapa 3: iniciar o contêiner montando todos os diretórios
Agora vem a parte principal. Observe o mapeamento de caminhos em cada parâmetro -v:
docker run -d --name my-nginx \
-p 80:80 -p 443:443 \
-v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /opt/nginx/conf.d:/etc/nginx/conf.d \
-v /opt/nginx/html:/usr/share/nginx/html \
-v /opt/nginx/logs:/var/log/nginx \
-v /opt/nginx/ssl:/etc/nginx/ssl \
nginx
Alguns pontos importantes:
-p 80:80 -p 443:443: expõe as portas HTTP e HTTPS, que serão usadas mais adiantenginx.conftermina com:ro, uma montagem somente leitura que impede alterações acidentais pelo processo no contêinerconf.dé montado como diretório completo, e não como arquivo isolado — isso faz diferença, como veremos a seguir
Quatro armadilhas comuns
Armadilha 1: o contêiner não recebe as alterações feitas com vim
Esse foi o primeiro problema que encontrei. Alterei nginx.conf no host, reiniciei o contêiner, mas nada mudou.
O motivo é que o vim pode substituir o arquivo durante a gravação e mudar seu inode. A montagem de um arquivo isolado fica associada ao inode anterior, então o contêiner continua vendo a versão antiga.
Há duas soluções:
- Opção A: editar com nano, que não muda o inode nesse fluxo
- Opção B: montar o diretório inteiro em vez de um único arquivo
Hoje prefiro a opção B. Ao montar o diretório, as mudanças de inode não atrapalham, e também fica mais fácil adicionar ou remover arquivos de configuração.
Armadilha 2: caminho incorreto no include
Entre no contêiner e confira nginx.conf:
docker exec -it my-nginx bash
cat /etc/nginx/nginx.conf | grep include
Confirme se esta linha existe:
include /etc/nginx/conf.d/*.conf;
Se você usar /opt/nginx/conf.d/*.conf, que é o caminho do host, estará errado. Dentro do contêiner, só os caminhos do próprio contêiner são válidos.
Armadilha 3: esquecer de montar o diretório conf.d
Montar apenas nginx.conf não basta. Se você adicionar uma configuração de site em conf.d no host, o contêiner não conseguirá vê-la.
Para verificar:
docker exec my-nginx ls /etc/nginx/conf.d
O resultado deve mostrar todos os arquivos existentes em /opt/nginx/conf.d no host.
Armadilha 4: permissões impedem o Nginx de ler a configuração
Esse problema é comum em sistemas Linux. Se as permissões forem restritivas demais, o processo do Nginx, que geralmente executa como usuário nginx, não conseguirá ler os arquivos.
Corrija as permissões:
chmod 644 /opt/nginx/conf/nginx.conf
chmod 644 /opt/nginx/conf.d/*.conf
Depois de alterar a configuração, crie o hábito de testar a sintaxe:
docker exec my-nginx nginx -t
Se aparecer syntax is ok, a configuração passou no teste.
Arquivo isolado ou diretório: qual montar?
Essa dúvida aparece com frequência. Minha recomendação é a seguinte:
Configuração principal nginx.conf: pode ser montada como arquivo isolado e somente leitura (:ro), porque costuma mudar pouco.
Diretório conf.d: monte o diretório inteiro para adicionar configurações de sites com flexibilidade.
html e logs: monte como diretórios.
Use esta regra: se você precisa gerenciar vários arquivos com flexibilidade, monte o diretório. Para uma configuração central que será versionada, um arquivo isolado com proteção de somente leitura também funciona.
Configurar HTTPS e a renovação automática do Let’s Encrypt
Certificado autoassinado para validar o ambiente de desenvolvimento
Em produção, você deve usar um certificado emitido por uma autoridade confiável. Para testes no ambiente de desenvolvimento, um certificado autoassinado resolve. Bastam alguns comandos:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /opt/nginx/ssl/nginx.key \
-out /opt/nginx/ssl/nginx.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Dev/CN=localhost"
O comando gera dois arquivos:
nginx.key: a chave privada, que nunca deve ser expostanginx.crt: o certificado
Depois, crie ssl.conf em /opt/nginx/conf.d/:
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Pontos importantes:
- O caminho de
ssl_certificateé o caminho dentro do contêiner (/etc/nginx/ssl), e não/opt/nginx/sslno host ssl_protocolshabilita apenas TLS 1.2 e 1.3, pois as versões antigas têm vulnerabilidades conhecidas- Não se esqueça de
-p 443:443ao iniciar o contêiner; sem isso, a porta HTTPS não fica exposta
Recarregue a configuração:
docker exec my-nginx nginx -s reload
Ao acessar https://localhost, o navegador avisará que o certificado não é confiável. Isso é esperado com um certificado autoassinado; prossiga apenas no seu ambiente de teste.
Let’s Encrypt: certificado gratuito para produção
O Let’s Encrypt é gratuito, automatizável e reconhecido pelos navegadores. Os certificados expiram em 90 dias, mas a renovação automática elimina o trabalho manual.
Aqui recomendo usar contêineres docker-compose e certbot, uma solução mais confiável do que manter o processo manualmente.
Veja o arquivo docker-compose.yml completo:
version: '3'
services:
nginx:
image: nginx:latest
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
networks:
- web
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
networks:
- web
networks:
web:
driver: bridge
Alguns pontos essenciais:
1. Montagem compartilhada dos certificados e arquivos de validação
./certbot/confé montado nos dois contêineres: certbot gera o certificado e Nginx o lê./certbot/wwwé usado na validação HTTP do Let’s Encrypt pelo método webroot
2. Nginx recarrega automaticamente a cada seis horas
O comando inicia um loop em segundo plano para recarregar a configuração a cada seis horas. Assim, um certificado renovado entra em vigor sem intervenção manual.
3. Certbot verifica a renovação a cada 12 horas
O Let’s Encrypt recomenda uma verificação diária; aqui, o intervalo de 12 horas oferece uma margem adicional.
Como solicitar o primeiro certificado
Crie primeiro uma configuração temporária chamada temp.conf em /opt/nginx/conf.d/ para a validação HTTP:
server {
listen 80;
server_name your-domain.com; # Substitua pelo seu domínio
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
Inicie os serviços:
docker-compose up -d
Solicite o certificado, substituindo your-domain.com e [email protected] pelos seus dados:
docker-compose run --rm certbot certonly --webroot \
-w /var/www/certbot \
-d your-domain.com \
--email [email protected] \
--agree-tos \
--no-eff-email
Se tudo der certo, você verá a mensagem Congratulations!. Os arquivos do certificado estarão em ./certbot/conf/live/your-domain.com/.
Agora você pode criar a configuração HTTPS definitiva. Substitua o conteúdo de temp.conf por:
server {
listen 80;
server_name your-domain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
# Otimizações de SSL
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# HSTS: força o uso de HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
Recarregue a configuração:
docker-compose exec nginx nginx -s reload
Como validar a renovação automática
Os certificados do Let’s Encrypt são válidos por 90 dias, e certbot tenta renová-los quando faltam 30 dias para expirar. Você pode testar o processo manualmente:
docker-compose run --rm certbot renew --dry-run
Se aparecer The dry run was successful, o teste funcionou.
Você também pode verificar os logs do cron para confirmar que a tarefa de renovação está funcionando:
docker-compose logs certbot
Medidas adicionais de segurança para HTTPS
Para reforçar a configuração SSL, você pode adicionar:
# OCSP Stapling: verificação do status do certificado
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/your-domain.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Impede a incorporação em iframe e reduz o risco de clickjacking
add_header X-Frame-Options DENY;
# Proteções adicionais contra conteúdo mal interpretado e XSS
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
Depois, use o SSL Labs para avaliar a configuração SSL. É possível chegar à nota A+ com esses ajustes.
Proxy reverso e comunicação entre contêineres Docker
Como funcionam as redes de contêineres
Ao usar Nginx como proxy para outros contêineres Docker, a configuração de rede costuma ser a parte mais trabalhosa. Talvez você já tenha tentado usar diretamente o IP de um contêiner e descoberto, após reiniciá-lo, que o IP mudou e a configuração deixou de funcionar.
O Docker oferece vários modos de rede. Estes são os dois mais comuns:
- bridge (ponte): modo padrão; os contêineres se comunicam por uma ponte virtual
- host: o contêiner usa diretamente a pilha de rede do host; oferece bom desempenho, mas menos isolamento
Para um proxy reverso com Nginx, recomendo uma rede bridge personalizada. Há três motivos:
- Os contêineres podem se comunicar pelo nome do serviço, sem depender de IPs que mudam
- Cada projeto fica isolado em sua própria rede
- O Docker fornece resolução DNS e descoberta de serviços automaticamente
Criar uma rede personalizada e executar os contêineres
Primeiro, crie uma rede personalizada:
docker network create my-app-network
Inicie o serviço de backend, supondo que seja uma API Node.js:
docker run -d \
--name backend-api \
--network my-app-network \
-e NODE_ENV=production \
my-backend:latest
Inicie o Nginx na mesma rede:
docker run -d \
--name my-nginx \
--network my-app-network \
-p 80:80 -p 443:443 \
-v /opt/nginx/conf.d:/etc/nginx/conf.d \
nginx
O ponto central é que os dois contêineres estão na mesma rede. Assim, a configuração do Nginx pode acessar o backend diretamente pelo nome backend-api.
Configuração prática de proxy reverso no Nginx
Crie api-proxy.conf em /opt/nginx/conf.d/:
upstream backend {
server backend-api:3000; # Nome do contêiner:porta
keepalive 32;
}
server {
listen 80;
server_name api.example.com;
# Proxy da API
location /api/ {
proxy_pass http://backend/;
# Encaminha os dados reais 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 WebSocket, se necessário
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Tempos limite
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Arquivos estáticos servidos diretamente pelo Nginx
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
Alguns detalhes fáceis de ignorar:
1. Tratamento de caminho em upstream e proxy_pass
Observe a barra final em proxy_pass http://backend/;. Com ela, uma solicitação para /api/users é encaminhada como http://backend/users, removendo o prefixo /api.
Se você usar proxy_pass http://backend;, sem a barra final, o destino será http://backend/api/users, preservando o caminho completo.
2. Importância do cabeçalho X-Forwarded-For
Se o backend precisa identificar o IP real do cliente, esse cabeçalho é essencial. Sem ele, o backend verá apenas o IP do contêiner do Nginx.
3. Pool de conexões keepalive
keepalive 32 no bloco upstream permite reutilizar conexões TCP e reduz o custo dos handshakes. Isso é útil em cenários de alta concorrência.
Simplificar o gerenciamento de vários contêineres com docker-compose
Criar a rede e iniciar cada contêiner manualmente dá trabalho. Com docker-compose, tudo pode ser iniciado de uma vez:
version: '3.8'
services:
backend:
image: my-backend:latest
container_name: backend-api
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://db:5432/mydb
networks:
- app-network
depends_on:
- db
nginx:
image: nginx:latest
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
- ./nginx/logs:/var/log/nginx
networks:
- app-network
depends_on:
- backend
db:
image: postgres:14
container_name: postgres-db
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=mydb
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db-data:
Inicie toda a pilha de serviços com um comando:
docker-compose up -d
O Docker fará automaticamente o seguinte:
- Criará uma rede chamada
app-network - Iniciará os contêineres conforme as dependências declaradas em
depends_on - Configurará a resolução DNS entre os contêineres
Na configuração do Nginx, você pode usar diretamente backend e db como nomes de host para acessar os serviços correspondentes.
Como diagnosticar problemas comuns de proxy
Problema 1: 502 Bad Gateway
Esse é o erro mais comum. As causas geralmente são:
- O serviço de backend não iniciou ou parou
- Nginx e backend não estão na mesma rede
- O backend está escutando na porta errada
Siga estes passos:
# Confirme se o serviço de backend está em execução
docker ps | grep backend
# Verifique a conexão de rede
docker network inspect my-app-network
# Entre no contêiner do Nginx e teste a conectividade
docker exec -it my-nginx sh
ping backend-api
curl http://backend-api:3000/health
Se o ping falhar, há um problema na rede. Se curl expirar, verifique em qual endereço e porta o backend está escutando.
Problema 2: tempo limite da solicitação
O tempo limite padrão do proxy é de 60 segundos. Se a API demora mais, por exemplo ao receber um arquivo grande ou executar um cálculo complexo, aumente os limites:
location /api/long-running/ {
proxy_pass http://backend/;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
Problema 3: corpo da solicitação POST ausente
Em alguns casos, a solicitação POST chega ao backend como GET ou sem corpo. Confira esta configuração:
location /api/ {
proxy_pass http://backend/;
proxy_request_buffering off; # Desabilita o buffer da solicitação
client_max_body_size 100M; # Permite upload de arquivos grandes
}
Balanceamento de carga entre vários backends
Se você tem várias instâncias do backend, Nginx pode distribuir a carga:
upstream backend_cluster {
least_conn; # Algoritmo de menor número de conexões
server backend-1:3000 weight=3; # Peso 3
server backend-2:3000 weight=1; # Peso 1
server backend-3:3000 backup; # Servidor reserva
keepalive 32;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend_cluster/;
# ... outras configurações de proxy
}
}
Há vários algoritmos de balanceamento:
round-robin(padrão): alternância entre os servidoresleast_conn: prioriza o servidor com menos conexõesip_hash: mantém o mesmo cliente no mesmo servidor com base no IP
Se um backend parar, Nginx encaminhará automaticamente o tráfego para os outros nós disponíveis.
Boas práticas e otimização de desempenho em produção
Gerenciamento da configuração: não publique arquivos sem controle
Deixar os arquivos de configuração soltos no servidor pode funcionar no desenvolvimento, mas não é adequado para produção.
Gerencie a configuração com Git
Minha abordagem é manter todas as configurações do Nginx em um repositório separado, com diretórios para cada ambiente. As vantagens são claras:
- O histórico mostra todas as alterações, e uma reversão pode ser feita com
git checkout - A equipe consegue revisar mudanças de configuração em pull requests
- A integração com CI/CD permite automatizar a implantação
Use modelos de configuração
Como as configurações de ambientes diferentes costumam ser parecidas, modelos com substituição de variáveis economizam trabalho. Durante a implantação, use envsubst para substituir os valores.
Gerenciamento de logs: não espere o disco encher
Nginx pode gerar muitos logs; em sites com tráfego alto, alguns gigabytes por dia não são incomuns. Sem controle, o disco pode encher e derrubar o contêiner.
Configure a rotação de logs
Configure logrotate no host para girar os logs diariamente, manter 14 dias e compactar os arquivos antigos. Depois da rotação, faça o Nginx reabrir os arquivos com nginx -s reopen; caso contrário, ele continuará gravando no arquivo antigo.
Centralize os logs
Se você tem vários servidores, pode enviar os logs para uma plataforma centralizada, como ELK, Loki ou um serviço em nuvem. Tanto o driver de logs do Docker quanto Promtail simplificam essa integração.
Recarregamento suave sem interromper usuários
Depois de alterar a configuração, evite docker restart. A reinicialização encerra conexões e pode interromper solicitações em andamento.
Use este fluxo:
# Primeiro, teste a sintaxe da configuração
docker exec my-nginx nginx -t
# Recarregue apenas se a sintaxe estiver correta
docker exec my-nginx nginx -s reload
reload faz um recarregamento suave: novos processos worker iniciam com a nova configuração, enquanto os antigos terminam as solicitações em andamento antes de sair. A troca ocorre sem interrupção perceptível.
Checklist de reforço de segurança
Antes de publicar em produção, verifique estes pontos:
1. Ocultar a versão do Nginx
Por padrão, páginas de erro podem revelar a versão do Nginx. Isso facilita ataques direcionados a vulnerabilidades conhecidas. Adicione server_tokens off; ao bloco http para ocultar a versão.
2. Limitar requisições contra DDoS
Uma proteção simples:
http {
# Limita a frequência de solicitações por IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# Limita o número de conexões simultâneas
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://backend/;
}
}
3. Montar arquivos de configuração como somente leitura
Acrescente :ro à montagem da configuração principal para impedir alterações acidentais por processos no contêiner.
4. Aplicar o princípio do menor privilégio
Confirme que nginx.conf contém user nginx;. Não execute o processo como root, pois isso aumenta muito o risco de segurança.
Ajustes para aproveitar o desempenho do Nginx
Otimizar o número de processos worker
worker_processes auto; # Ajusta automaticamente ao número de núcleos da CPU
worker_cpu_affinity auto; # Define a afinidade de CPU
Com auto, Nginx detecta automaticamente o número de núcleos da CPU.
Otimizar o número de conexões
events {
worker_connections 2048; # Máximo de conexões por worker
use epoll; # epoll oferece o melhor desempenho no Linux
}
O máximo teórico de conexões simultâneas é worker_processes * worker_connections. Na prática, também é preciso considerar o limite de descritores de arquivo definido por ulimit -n.
Compressão gzip
Comprimir conteúdo de texto pode reduzir o volume transferido em 60% a 80%:
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6; # Nível de 1 a 9; 6 equilibra desempenho e taxa de compressão
gzip_types
text/plain
text/css
text/xml
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
gzip_min_length 1000; # Não comprime arquivos menores que 1 KB para evitar custo de CPU
}
Cache de arquivos estáticos
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d; # Cache do navegador por 30 dias
add_header Cache-Control "public, immutable";
}
Suporte a HTTP/2
HTTP/2 pode melhorar bastante o desempenho e é simples de habilitar:
server {
listen 443 ssl http2; # Basta acrescentar http2
# ... outras configurações
}
O pré-requisito é HTTPS, pois HTTP/2 depende de TLS nesse cenário.
Monitoramento e health checks
Por fim, não deixe o monitoramento de lado. Uma opção é usar Prometheus e Grafana com nginx-prometheus-exporter para expor métricas. Habilite stub_status na configuração do Nginx, restrinja o acesso à rede interna do Docker, faça Prometheus coletar as métricas e use Grafana para visualizá-las.
Conclusão
O essencial cabe em quatro pontos:
Montagem da configuração: prefira montar diretórios a arquivos isolados, proteja a configuração principal como somente leitura e não se esqueça de conf.d e ssl. Evite o problema de inode causado pelo vim.
HTTPS: use um certificado autoassinado para validações no desenvolvimento e Let’s Encrypt com Certbot em produção. docker-compose simplifica a renovação automática.
Proxy reverso: prefira uma rede bridge personalizada e use os nomes dos contêineres na comunicação. Configure keepalive no upstream para melhorar desempenho e confiabilidade.
Produção: versione a configuração com Git, faça rotação de logs, use reload em vez de restart e aplique as medidas de segurança necessárias.
Nginx no Docker parece simples, mas há muitos detalhes. Quando você entende cada um deles, consegue montar uma arquitetura de serviços web estável e confiável do desenvolvimento à produção.
Se este artigo ajudou você a evitar algumas armadilhas ou resolveu um problema antigo, vale a pena colocar a configuração em prática e adaptar os exemplos ao seu ambiente.
Uma última sugestão: guarde os modelos de configuração deste artigo para reutilizá-los. Não há motivo para reconstruir tudo do zero em cada projeto.
Fluxo completo para implantar Nginx no Docker
Monte arquivos de configuração, habilite HTTPS e configure um proxy reverso, evitando problemas comuns de configuração e comunicação entre contêineres
⏱️ Estimated time: 1 hr
- 1
Step 1: Montar a configuração de cinco formas corretas
Cinco formas corretas de montar a configuração:
• Montar o arquivo principal: -v ./nginx.conf:/etc/nginx/nginx.conf
• Montar o diretório de configuração: -v ./conf.d:/etc/nginx/conf.d
• Usar um volume do Docker
• Configurar com docker-compose
• Usar ConfigMap em um ambiente Kubernetes
Problemas comuns:
• As alterações em nginx.conf não entram em vigor dentro do contêiner
• É necessário montar corretamente o arquivo ou diretório de configuração com -v
• O formato do arquivo de configuração precisa ser válido
Boas práticas:
• Prefira montar diretórios a montar arquivos isolados
• Monte a configuração principal como somente leitura
• Não se esqueça dos diretórios conf.d e ssl
• Evite o problema de inode causado pelo vim - 2
Step 2: Configurar HTTPS e a renovação automática do Let's Encrypt
Configuração HTTPS:
• Usar certificados gratuitos do Let's Encrypt
• Configurar a renovação automática com certbot renew
• Montar o diretório de certificados: -v ./certs:/etc/nginx/certs
• Configurar os caminhos dos certificados SSL
• Habilitar HTTP/2 e TLS 1.3
Configuração do Let's Encrypt:
• Obter um certificado com certbot certonly --standalone
• Testar a renovação com certbot renew --dry-run
• Montar os certificados no contêiner: -v ./letsencrypt:/etc/letsencrypt
• Configurar nginx.conf para usar os certificados - 3
Step 3: Configurar o proxy reverso e aplicar boas práticas de produção
Configuração do proxy reverso:
• Apontar o upstream para o contêiner de backend
• Usar o nome do contêiner ou do serviço: proxy_pass http://backend:8080
• Configurar health checks
• Tratar problemas de CORS
• Configurar balanceamento de carga
Boas práticas de produção:
• Gerenciar vários contêineres com docker-compose
• Configurar health checks
• Definir limites de recursos
• Configurar rotação de logs
• Gerenciar a configuração com variáveis de ambiente
• Atualizar as imagens regularmente
Nginx no Docker parece simples, mas envolve muitos detalhes. Com esses pontos bem resolvidos, você consegue montar uma arquitetura de serviços web estável do desenvolvimento à produção.
FAQ
Por que as alterações na configuração do Nginx no Docker não entram em vigor?
Cinco formas corretas de montar a configuração:
1) Montar o arquivo principal: -v ./nginx.conf:/etc/nginx/nginx.conf
2) Montar o diretório: -v ./conf.d:/etc/nginx/conf.d
3) Usar um volume do Docker
4) Configurar com docker-compose
5) Usar ConfigMap em um ambiente Kubernetes
Boas práticas:
• Prefira montar diretórios a montar arquivos isolados
• Monte a configuração principal como somente leitura
• Não se esqueça dos diretórios conf.d e ssl
• Evite o problema de inode causado pelo vim
Como configurar HTTPS no Nginx executado em Docker?
• Use certificados gratuitos do Let's Encrypt
• Configure a renovação automática com certbot renew
• Monte o diretório de certificados: -v ./certs:/etc/nginx/certs
• Configure os caminhos dos certificados SSL
• Habilite HTTP/2 e TLS 1.3
Configuração do Let's Encrypt:
• Obtenha um certificado com certbot certonly --standalone
• Teste a renovação com certbot renew --dry-run
• Monte os certificados no contêiner: -v ./letsencrypt:/etc/letsencrypt
• Configure nginx.conf para usar os certificados
Como configurar um proxy reverso com Nginx no Docker?
• Aponte o upstream para o contêiner de backend
• Use o nome do contêiner ou do serviço: proxy_pass http://backend:8080
• Configure health checks
• Trate problemas de CORS
• Configure o balanceamento de carga
Comunicação entre contêineres:
• Crie uma rede personalizada com docker-compose
• Garanta que os contêineres estejam na mesma rede
• Acesse o serviço pelo nome do serviço ou do contêiner
• Aponte o upstream para o serviço de backend
Quais são as boas práticas para usar Nginx no Docker em produção?
• Gerencie vários contêineres com docker-compose
• Configure health checks
• Defina limites de recursos
• Configure rotação de logs
• Gerencie a configuração com variáveis de ambiente
• Atualize as imagens regularmente
Nginx no Docker parece simples, mas envolve muitos detalhes. Com esses pontos bem resolvidos, você consegue montar uma arquitetura de serviços web estável do desenvolvimento à produção.
Sugestão: guarde os modelos de configuração deste artigo para reutilizá-los em outras implantações.
17 min de leitura · Publicado em: 18 dez 2025 · Atualizado em: 4 set 2026
Guia prático Docker
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Como implantar MySQL com Docker: persistência e replicação
Implante MySQL com Docker usando volumes, Docker Compose e replicação. Resolva falhas de conexão e aplique segurança, backups e limites de recursos em produção.
Parte 24 de 34
Próximo
Segurança de imagens Docker: varredura e correção com Trivy e integração ao CI/CD
76% das imagens no Docker Hub têm vulnerabilidades de segurança. Este guia mostra como usar o Trivy, corrigir falhas de forma sistemática e automatizar a varredura no CI/CD, com comandos completos para criar aplicações em contêiner mais seguras.
Parte 26 de 34



Comentários
Entre com GitHub para comentar