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:

    yaml
    # 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:
    Dica
    O banco de dados e Redis ficam apenas na rede backend — o Nginx não pode acessá-los diretamente. Os serviços de aplicação estão em ambas as redes: recebem tráfego do Nginx (frontend) e acessam banco/cache (backend).

    Configuração Nginx para rotear por domínio

    Arquivo de configuração Nginx que roteia para os containers corretos:

    nginx
    # 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:

    yaml
    # 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:

    yaml
    # 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:

    yaml
    # 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.

    Perguntas frequentes