← Voltar ao blog

Docker, Nginx e HTTPS em uma VPS: uma arquitetura inicial segura

Como organizar uma aplicação em Docker atrás de Nginx com HTTPS, portas privadas, variáveis de ambiente e um caminho simples de deploy.

·
  • #docker
  • #nginx
  • #https
  • #vps
  • #deploy

Rodar uma aplicação em Docker não significa publicar cada container na internet. Uma arquitetura inicial mais segura mantém a aplicação e o banco em uma rede privada e expõe apenas um proxy reverso, responsável por receber HTTPS e encaminhar a requisição para o serviço certo.

Essa separação reduz portas abertas, centraliza certificados e permite hospedar mais de uma aplicação na mesma VPS sem criar uma configuração diferente para cada uma.

O desenho básico

Pense em três camadas:

  1. Nginx recebe tráfego público nas portas 80 e 443.
  2. Aplicação atende em uma porta privada ou rede Docker interna.
  3. Banco e cache não recebem conexões diretas da internet.

O domínio aponta para a VPS. Nginx termina o TLS, redireciona HTTP para HTTPS e encaminha, por exemplo, app.exemplo.com para o container da aplicação. O banco só é alcançado pela aplicação dentro da rede definida no Compose.

Evite publicar tudo no host

Ao usar ports no Compose, você mapeia uma porta do container para a máquina. Isso é útil para o proxy, mas geralmente desnecessário para banco e serviços internos. Uma configuração inicial pode manter a aplicação escutando somente no loopback:

services:
  app:
    image: minha-app:1.0.0
    ports:
      - "127.0.0.1:3000:3000"
    env_file: .env
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  postgres_data:

Nesse caso, Nginx no host encaminha para 127.0.0.1:3000, mas a porta não fica pública. Se Nginx também rodar em Docker, os serviços podem conversar por uma rede Docker compartilhada, sem mapeamento para o host.

Proxy reverso e HTTPS

O proxy deve saber qual domínio atende e qual serviço recebe o tráfego. Em uma aplicação web, preserve os cabeçalhos que informam protocolo e IP original, pois eles afetam redirecionamentos, cookies seguros e logs.

server {
  server_name app.exemplo.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Depois que o DNS estiver apontando para a VPS, emita um certificado e ative renovação automática. Teste o redirecionamento de HTTP, o certificado no domínio final e o comportamento de URLs com e sem www, se ambos forem usados.

Variáveis e persistência

Use um .env fora do Git, com permissão restrita. Imagens são descartáveis; os dados não podem ser. Bancos, uploads e arquivos gerados precisam de volumes ou armazenamento externo definido conscientemente.

Antes de atualizar uma imagem, saiba onde os dados estão e tenha backup. Atualizar um container é fácil; recuperar um volume perdido não é.

Um deploy que dá para repetir

Identifique imagens por versão ou hash, evite depender apenas de latest e registre o comando de atualização. Um fluxo inicial pode ser simples: baixar a nova imagem, rodar migrações necessárias, reiniciar o serviço e verificar um endpoint de saúde.

Tenha também um caminho de volta. Se a versão nova falhar, você deve conseguir subir a imagem anterior sem improvisar durante uma indisponibilidade.

Onde esse desenho começa a mudar

Para vários serviços, múltiplos domínios ou deploys frequentes, ferramentas como Coolify ou Dokploy podem reduzir trabalho operacional. Ainda assim, elas continuam precisando de firewall, domínio, backups e atualização. A ferramenta muda a interface; não elimina as responsabilidades de quem administra o servidor.

O Guia de Configuração de VPS reúne esse desenho com instalação de Docker, Nginx, HTTPS, deploy, templates de Compose e uma estratégia de backup para seguir do começo ao fim.