Docker em VPS: por onde começar
Com o Docker, você roda no servidor um bot, um site, um banco de dados e o monitoramento sem que um atrapalhe o outro, e mudar para outra VPS se resume a copiar alguns arquivos e os dados. A instalação leva cinco minutos; os problemas de verdade aparecem depois: portas do banco abertas para a internet, logs de dezenas de gigabytes e dados que sumiram junto com o contêiner. Veja como evitá-los desde o início.
Um contêiner é um aplicativo com todas as bibliotecas e configurações, empacotado numa imagem. No servidor, ele sobe com um único comando e funciona do mesmo jeito em qualquer Linux. Para uma VPS, isso significa: você não precisa ajustar versões de Python, Node.js ou PostgreSQL ao sistema, vários projetos convivem no mesmo servidor, e o arquivo compose.yaml descreve todo o conjunto de serviços de um jeito que permite subi-lo num servidor novo em minutos.
Que VPS o Docker precisa
Virtualização KVM. O Docker usa recursos do kernel Linux: namespaces, cgroups, regras de rede próprias. Em KVM, o servidor tem kernel próprio, e o Docker funciona sem restrições. Em OpenVZ e LXC, o kernel é compartilhado com outros clientes, e ali o Docker ou não sobe, ou funciona com restrições que dependem do provedor. Mais detalhes no artigo KVM ou OpenVZ: o que escolher.
Memória e núcleos. O Docker em si ocupa pouco; quem consome memória são os contêineres. Referências:
- 1 GB: um ou dois contêineres leves, como um bot, uma API pequena ou o monitoramento;
- 2 núcleos e 2 GB: um site com banco de dados e proxy reverso, alguns serviços pequenos;
- 2–4 núcleos e 4 GB: vários projetos, PostgreSQL, Redis, build de imagens no próprio servidor;
- a partir de 8 GB: GitLab, n8n com muitos fluxos, Elasticsearch e outros serviços pesados.
Disco. As imagens ocupam espaço: uma imagem base com Python ou Node.js tem centenas de megabytes, e as versões antigas se acumulam a cada atualização. Pegue a partir de 30 GB em NVMe; para fazer build de imagens no servidor, mais.
Pelo catálogo da accsly em 1 de novembro de 2026, um plano KVM com 2 núcleos e 2 GB de memória custa na mediana do mercado cerca de US$ 15 por mês, e um quarto desses planos sai por menos de US$ 9. Com 2 núcleos e 4 GB, cerca de US$ 20, e um quarto abaixo de US$ 12 (valores convertidos de rublos e arredondados). Seleções: VPS para Docker, VPS KVM, VPS com 4 GB. Para testar, a cobrança por hora é prática: um servidor por uma noite custa centavos.
Antes de instalar
Pegue um Ubuntu 22.04 ou 24.04 LTS ou um Debian 12 recém-instalado e comece pela proteção básica: atualizações, login por chave, usuário separado, firewall. Está tudo no artigo Primeiros 10 passos depois de comprar uma VPS: segurança. Um painel de controle de sites normalmente não é necessário num servidor com contêineres; o porquê está no artigo Painéis de controle de servidor.
Instalação a partir do repositório oficial
O pacote docker.io do repositório do Ubuntu muitas vezes está atrás da versão atual e nem sempre traz o Compose. É mais confiável instalar a partir do repositório do Docker. Comandos para Ubuntu conforme a documentação oficial:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
No Debian, os comandos são os mesmos, só que nos endereços linux/ubuntu vira linux/debian, e no lugar de UBUNTU_CODENAME usa-se VERSION_CODENAME. Confira a instalação:
sudo docker run hello-world
docker compose version
Existe também o instalador de um comando só em get.docker.com, mas a própria documentação do Docker não o recomenda para servidores de produção: ele instala muitos pacotes sem pedir confirmação e sempre pega a versão mais recente.
O grupo docker. Para não digitar sudo antes de cada comando, o usuário é adicionado ao grupo docker: sudo usermod -aG docker $USER, seguido de um novo login. Lembre que isso equivale a permissões de root: um membro do grupo pode rodar um contêiner com acesso a todo o sistema de arquivos do servidor. Coloque ali só a sua própria conta de trabalho.
Primeiro projeto com Docker Compose
Comandos docker run avulsos com uma dezena de parâmetros são esquecidos rapidamente. É mais prático descrever o projeto num arquivo compose.yaml numa pasta própria, por exemplo /opt/app. Exemplo de um aplicativo web com banco PostgreSQL:
services:
app:
image: ghcr.io/example/app:1.4.2
restart: unless-stopped
environment:
DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
ports:
- "127.0.0.1:8080:8080"
depends_on:
- db
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Coloque a senha ao lado, num arquivo .env com a linha DB_PASSWORD=..., e impeça que outros usuários o leiam: chmod 600 .env. Para subir: docker compose up -d; para ver o log: docker compose logs -f app; para parar: docker compose down.
Três coisas neste exemplo são importantes:
restart: unless-stopped: os contêineres voltam a subir depois de uma reinicialização do servidor;- o banco não tem a seção
ports: o aplicativo o enxerga pelo nomedbna rede interna do projeto, e de fora ele fica inacessível; - a porta do aplicativo é publicada só em
127.0.0.1, e quem a expõe para fora é o nginx ou o Caddy, com certificado TLS.
Portas e firewall
Esta é a principal armadilha para iniciantes. Quando um contêiner publica uma porta como "5432:5432", o Docker adiciona por conta própria regras no iptables, e essa porta fica aberta para a internet independentemente das regras do ufw ou do firewalld. A documentação do Docker avisa isso com todas as letras: as portas publicadas pelos contêineres ignoram as regras do firewall. É exatamente assim que bancos PostgreSQL, MongoDB e Redis sem senha costumam acabar expostos na internet.
A regra é simples: publique para fora só o que deve ser acessível a todos, normalmente as portas 80 e 443 do proxy reverso. O resto fica sem a seção ports ou vinculado a 127.0.0.1. Para ver o que o servidor realmente está escutando, use ss -tlnp; de fora, a partir de outro computador, nc -zv IP-do-servidor 5432.
Logs e espaço em disco
Por padrão, o Docker grava a saída dos contêineres em arquivos JSON sem limite de tamanho. Um aplicativo falante enche o disco em alguns meses, e o servidor para. Limite os logs de todos os contêineres no arquivo /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Depois, sudo systemctl restart docker. A configuração vale para os contêineres criados depois dela, então recrie os projetos: docker compose up -d --force-recreate.
O segundo devorador de espaço são as imagens antigas. Quanto está ocupado, mostra o docker system df; para apagar as imagens sem uso, docker image prune -a. Não rode docker system prune --volumes sem saber o que está fazendo: ele apaga também os volumes dos projetos parados, junto com os dados.
Onde ficam os dados e como copiá-los
Tudo o que o aplicativo gravou dentro do contêiner some quando ele é recriado. Só se preserva o que está em volumes (volumes) ou em pastas do servidor montadas no contêiner. Antes de rodar qualquer imagem, veja na documentação dela quais pastas precisam ir para um volume: no PostgreSQL é /var/lib/postgresql/data; em outros aplicativos, os caminhos são outros.
Copiar os arquivos do banco com ele rodando não é confiável. Faça um dump pelo próprio contêiner:
docker compose exec -T db pg_dump -U app app | gzip > /backup/app-$(date +%F).sql.gz
Coloque esse comando no cron e mande as cópias para fora do servidor, junto com o compose.yaml e o .env. Como organizar o armazenamento externo e a verificação das cópias está no artigo Backups de VPS: estratégias e ferramentas.
Atualização dos contêineres
No compose.yaml, indique uma versão específica da imagem (postgres:16, app:1.4.2), e não latest: assim a atualização acontece quando você planejou, e não num reinício qualquer. A ordem da atualização:
- fazer o dump do banco;
- trocar a versão no
compose.yaml; docker compose pulledocker compose up -d;- conferir o log e o funcionamento do aplicativo e, depois, apagar a imagem antiga.
Versões principais de bancos de dados, como PostgreSQL 16 → 17, não se atualizam assim: a versão nova exige migrar os dados por dump e importação. O sistema do servidor e o próprio Docker são atualizados com o apt upgrade de sempre.
Próximos passos
Quando o servidor tem vários projetos, vale instalar um proxy reverso que obtém os certificados sozinho e um monitoramento de disponibilidade. Para um bot em Python ou Node.js num contêiner, basta um servidor pequeno; detalhes no artigo VPS para bot do Telegram. Se os contêineres se multiplicam e um servidor não dá conta, o passo seguinte é ter vários servidores com um orquestrador; os planos estão na seleção VPS para Kubernetes. Para automação e CI em contêineres, há as seleções VPS para n8n e VPS para GitLab.