Nginx com Docker Compose como gateway
Quando você roda múltiplos serviços com Docker Compose, o Nginx funciona como gateway — recebe todas as requisições na porta 80/443 e roteia para o container correto pela rede interna do Docker. Elimina a necessidade de expor portas individuais de cada serviço e centraliza SSL.
Nginx como serviço no Docker Compose
Estrutura completa com Nginx, app e banco de dados:
# docker-compose.yml
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
- /etc/letsencrypt:/etc/letsencrypt:ro
depends_on:
- app
- api
networks:
- frontend
app:
build: ./app
restart: always
environment:
DATABASE_URL: postgresql://user:pass@postgres:5432/db
depends_on:
- postgres
networks:
- frontend
- backend
# NÃO expor porta — apenas Nginx acessa internamente
api:
build: ./api
restart: always
environment:
DATABASE_URL: postgresql://user:pass@postgres:5432/db
REDIS_URL: redis://redis:6379
networks:
- frontend
- backend
postgres:
image: postgres:17-alpine
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- backend # apenas rede interna — não acessível pelo Nginx
redis:
image: redis:7-alpine
restart: always
networks:
- backend
networks:
frontend: # Nginx ↔ app/api
backend: # app/api ↔ banco/redis
volumes:
postgres_data:Configuração Nginx para rotear por domínio
Arquivo de configuração Nginx que roteia para os containers corretos:
# nginx/conf.d/default.conf
# Redirecionar HTTP → HTTPS
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
# Frontend (app)
server {
listen 443 ssl http2;
server_name seudominio.com.br www.seudominio.com.br;
ssl_certificate /etc/letsencrypt/live/seudominio.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/seudominio.com.br/privkey.pem;
location / {
# "app" é o nome do serviço no docker-compose.yml
# Docker resolve automaticamente para o IP do container
proxy_pass http://app:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}
# API
server {
listen 443 ssl http2;
server_name api.seudominio.com.br;
ssl_certificate /etc/letsencrypt/live/api.seudominio.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.seudominio.com.br/privkey.pem;
location / {
proxy_pass http://api:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}Renovar certificados Let's Encrypt com Nginx em Docker
Como usar Certbot junto com Nginx containerizado:
# Opção 1: Certbot na máquina host (fora do Docker)
# O Let's Encrypt valida via porta 80 (challenge HTTP)
# Adicionar volume do Let's Encrypt ao compose:
# nginx: volumes: - /etc/letsencrypt:/etc/letsencrypt:ro
# Emitir certificado com Nginx parado temporariamente:
sudo systemctl stop nginx || true # parar Nginx do host se existir
sudo certbot certonly --standalone -d seudominio.com.br
docker compose restart nginx # reiniciar Nginx do Docker
# Opção 2: Certbot como container no compose
services:
certbot:
image: certbot/certbot
volumes:
- /etc/letsencrypt:/etc/letsencrypt
- /var/www/certbot:/var/www/certbot
command: certonly --webroot -w /var/www/certbot -d seudominio.com.br --non-interactive --agree-tos --email admin@seudominio.com.br
profiles: ["certbot"] # rodar manualmente: docker compose --profile certbot run certbot
# No nginx.conf — servir o webroot challenge:
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}Traefik: alternativa ao Nginx para Docker
Traefik detecta containers automaticamente e configura rotas via labels:
# docker-compose.yml com Traefik
services:
traefik:
image: traefik:v3
restart: always
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=admin@seudominio.com.br"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_data:/letsencrypt
app:
build: ./app
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host('seudominio.com.br')"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=3000"
volumes:
traefik_data:Escalar serviços com --scale e load balancing automático
Docker Compose com Nginx faz load balancing entre múltiplas réplicas:
# docker-compose.yml — sem port mapping fixo para escalar
services:
app:
build: ./app
restart: always
# SEM "ports:" — Nginx acessa pela rede interna
environment:
DATABASE_URL: postgresql://user:pass@postgres:5432/db
networks:
- frontend
- backend
# Subir 3 réplicas do app:
docker compose up -d --scale app=3
# O Docker Compose cria um DNS interno que resolve "app" para todos os IPs
# O Nginx com upstream faz round-robin automaticamente:
# nginx/conf.d/app.conf:
upstream app_cluster {
server app:3000; # DNS round-robin automático do Docker
keepalive 32;
}
server {
location / {
proxy_pass http://app_cluster;
}
}
# Verificar os containers rodando:
docker compose ps
# app-1, app-2, app-3 todas UP$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.