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:
- Nginx recebe tráfego público nas portas 80 e 443.
- Aplicação atende em uma porta privada ou rede Docker interna.
- 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.