SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

Docker numa VPS: o que realmente muda

Docker numa VPS usa o mesmo engine, mas a RAM acaba, portas publicadas ignoram a UFW, contentores não reiniciam e o disco pode ficar cheio.

O que muda quando executa Docker numa VPS

O Docker numa VPS usa o mesmo engine e as mesmas imagens que o Docker no seu portátil, por isso todos os comandos que já conhece continuam a funcionar. O que muda é o espaço disponível à volta dele. Um portátil tem memória livre, uma firewall que ninguém está a analisar e um disco suficientemente grande para nunca precisar de o consultar. Um servidor alugado tem um limite fixo de memória, um endereço IP público que começa a ser analisado poucos minutos depois do arranque e um sistema de ficheiros raiz que o Docker vai preencher sem pedir autorização.

Quatro diferenças causam a maioria dos problemas numa máquina pequena:

  • A memória é finita e o kernel resolve uma falta de memória terminando um processo.
  • Uma porta publicada passa diretamente pela UFW (uncomplicated firewall), porque o Docker escreve as suas próprias regras de firewall.
  • Os contentores não voltam a arrancar depois de um reboot, a menos que tenha configurado isso antecipadamente.
  • As imagens, os contentores, os volumes e a cache de build crescem até o disco ficar cheio.

Cada secção abaixo identifica a falha, a mensagem que verá efetivamente e o guia que a corrige em profundidade. Se ainda não escreveu um ficheiro Compose, leia primeiro Noções básicas do Docker Compose numa VPS e volte depois. Esta página pressupõe que já consegue iniciar uma stack.

Quanta RAM um contentor Docker utiliza?

Menos do que a maioria das pessoas espera. Um contentor é um processo num cgroup (grupo de controlo), não uma máquina virtual. Por isso, não existe um kernel convidado nem uma alocação fixa. O custo corresponde ao que o processo no seu interior utiliza. É por isso que uma stack completa cabe em 2 GB quando a mesma stack criada com máquinas virtuais não caberia.

Os valores abaixo são números típicos em idle para imagens padrão no Ubuntu 24.04, com a configuração predefinida, lidos a partir de docker stats alguns minutos depois do arranque. Servem como ponto de partida para o planeamento, não como benchmark da sua carga de trabalho. Execute docker stats --no-stream no seu próprio servidor antes de confiar em qualquer valor, incluindo estes.

ChartTypical idle container memory, stock images, megabytes
The data behind this chart
[
  {
    "label": "nginx",
    "idle_mb": 8,
    "budget_mb": 64
  },
  {
    "label": "Redis 7",
    "idle_mb": 12,
    "budget_mb": 128
  },
  {
    "label": "Traefik v3",
    "idle_mb": 40,
    "budget_mb": 128
  },
  {
    "label": "PostgreSQL 16",
    "idle_mb": 45,
    "budget_mb": 512
  },
  {
    "label": "Uptime Kuma",
    "idle_mb": 95,
    "budget_mb": 256
  },
  {
    "label": "MariaDB 11",
    "idle_mb": 190,
    "budget_mb": 512
  },
  {
    "label": "Nextcloud (Apache)",
    "idle_mb": 210,
    "budget_mb": 768
  }
]

As duas colunas têm funções diferentes. idle_mb indica o que o contentor utiliza quando não está a fazer nada. budget_mb indica quanto deve reservar no planeamento, porque a utilização real não ocorre em idle. O PostgreSQL fica perto de 45 MB em idle e precisa de 512 MB quando as ligações, ordenações e a cache estão ativas. Faça o planeamento com a coluna de orçamento. Faça a depuração com a coluna de idle.

Observe o perfil dessas 7 linhas. O nginx fica em idle com 8 MB e o Nextcloud com 210 MB. O proxy à frente das suas aplicações consome muito pouca memória. São a base de dados e a aplicação PHP que determinam a dimensão necessária do servidor.

Tenha atenção a docker stats: o valor de memória inclui a cache de páginas carregada pelas leituras de ficheiros do próprio contentor, por isso aumenta durante algum tempo depois do arranque e depois estabiliza. Monitorize-o durante uma hora antes de concluir que existe uma fuga de memória.

Dimensionar um VPS: o que cabe em 2 GB, 4 GB e 8 GB

Comece por reservar a parte do host. O kernel, o systemd, o journald, o sshd e o daemon do Docker usam a mesma RAM que os seus contentores, e dockerd com containerd ocupam cerca de 100 MB. Também precisa de memória livre para a cache de páginas e para o pico de utilização que ocorre quando é criada uma imagem ou executado um dump da base de dados.

ChartRAM budget by plan size, megabytes
The data behind this chart
[
  {
    "plan": "2 GB VPS",
    "total_mb": 2048,
    "host_reserve_mb": 768,
    "container_mb": 1280
  },
  {
    "plan": "4 GB VPS",
    "total_mb": 4096,
    "host_reserve_mb": 1024,
    "container_mb": 3072
  },
  {
    "plan": "8 GB VPS",
    "total_mb": 8192,
    "host_reserve_mb": 1536,
    "container_mb": 6656
  }
]

host_reserve_mb cobre o sistema operativo, o daemon do Docker e a margem que mantém o servidor responsivo sob carga. O que sobra é container_mb, e esse é o único valor que pode utilizar. A reserva aumenta com o plano, de 768 MB no servidor mais pequeno para 1536 MB no maior, porque um servidor maior executa mais contentores, escreve mais logs e precisa de mais cache de páginas.

Um plano de 2 GB deixa 1280 MB para os contentores. Reserve 512 MB para o PostgreSQL e 128 MB para o Traefik, e metade desse valor já desapareceu. O restante chega para duas aplicações pequenas, com cerca de 256 MB cada. É um servidor real e útil. Não é espaço suficiente para acrescentar o Nextcloud e um cluster de pesquisa.

Um plano de 4 GB deixa 3072 MB, o suficiente para executar ao mesmo tempo uma base de dados, um reverse proxy, três aplicações e um contentor de monitorização. Este é o menor tamanho que vale a pena usar para algo importante, porque a memória livre absorve os efeitos de uma implementação problemática.

Um plano de 8 GB deixa 6656 MB dos seus 8192 MB, e o limite normalmente passa da memória para a CPU ou para o débito do disco. Há um tipo de contentor que dimensiona o consumo a partir da configuração, e não da carga: um servidor de modelos local reserva cache KV proporcionalmente à sua janela de contexto, por isso aumentar o num_ctx do Ollama pode acrescentar gigabytes ao orçamento antes de chegar um único pedido. Se os cálculos mostrarem que a sua stack não cabe, compre o plano maior em vez de tentar contornar o problema com afinações: quanto custa realmente um VPS explica o valor mensal dos gigabytes adicionais.

Duas regras mantêm os cálculos realistas. Defina um limite de memória para cada serviço, para que um processo descontrolado não derrube todo o servidor. E não utilize a totalidade do orçamento, porque docker compose build e pg_dump precisam de memória precisamente no pior momento. Limites de memória no Docker Compose apresenta a sintaxe e as armadilhas.

Porque é que o meu container termina com o código 137?

Porque o kernel o terminou. 137 é 128 mais 9, e o sinal 9 é SIGKILL. O container pediu mais memória do que aquela que lhe era permitida, e o OOM killer terminou-o.

CONTAINER ID   IMAGE         STATUS
9f2c1a4d7b3e   postgres:16   Exited (137) 4 minutes ago

Confirme a causa em vez de adivinhar:

docker inspect my-db | grep -i oomkilled
sudo journalctl -k | grep -i "out of memory"

"OOMKilled": true significa que o container atingiu o seu próprio limite de cgroup, e o log do kernel identifica o processo escolhido:

Memory cgroup out of memory: Killed process 2417 (postgres) total-vm:1284416kB

Este é o caso favorável, porque o impacto ficou limitado a um container. O caso problemático é um container sem qualquer limite. Sem um limite, o teto é a memória de toda a máquina. Uma fuga de memória num serviço esgota os recursos do host, e o kernel escolhe depois uma vítima com base no consumo em todo o sistema. A linha do log perde o prefixo Memory cgroup e fica Out of memory: Killed process 2417 (postgres). O processo escolhido é frequentemente a sua base de dados, enquanto o container que causou a fuga continua a executar. Por isso, definir um limite para todos os serviços é mais importante do que acertar no valor exato de qualquer limite individual.

A swap altera o momento em que o problema surge, não a aritmética. A maioria das imagens VPS é fornecida sem swap. Verifique com swapon --show, que não imprime nada quando não existe swap. Um ficheiro de swap dá ao kernel um local para colocar páginas inativas, o que lhe compra alguns minutos para detetar o problema.

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

free -h deve agora mostrar um total diferente de zero na linha Swap. A swap não adiciona RAM. Uma máquina sob pressão constante de memória fica suficientemente lenta para impedir o acesso por SSH e a correção do problema. Trate a swap como uma margem de segurança e corrija o dimensionamento.

Por que o UFW não bloqueia a porta publicada pelo Docker?

Porque o tráfego nunca chega à cadeia protegida pelo UFW. Quando publica uma porta com -p 5432:5432 ou com uma entrada ports: do compose, o daemon escreve uma regra DNAT (tradução de endereços de rede de destino) na tabela nat e uma regra de aceitação na sua própria cadeia DOCKER. Um pacote destinado a um contentor é encaminhado para esse contentor, em vez de ser entregue ao host. Por isso, segue o caminho FORWARD e nunca passa pelas regras INPUT escritas pelo UFW.

Pode observar este comportamento no servidor:

sudo ufw status | grep 5432
sudo iptables -t nat -L DOCKER -n | grep 5432

O UFW pode mostrar 5432 DENY IN Anywhere enquanto a tabela nat contém uma regra DNAT tcp ... to:172.18.0.2:5432 para a mesma porta. A partir de outra máquina, nc -vz your.server.ip 5432 continua a estabelecer ligação. A base de dados está acessível através da Internet pública, embora a firewall indique o contrário.

A correção é publicar menos portas. Os contentores do mesmo projeto compose partilham uma rede e conseguem aceder uns aos outros pelo nome do serviço. Por isso, uma base de dados que serve apenas a aplicação ao lado não precisa de qualquer entrada ports:. Quando precisar de acesso local, associe a publicação à interface de loopback:

services:
  db:
    image: postgres:16
    ports:
      - "127.0.0.1:5432:5432"

Depois de docker compose up -d, nc -vz your.server.ip 5432 falha a partir do exterior, enquanto psql -h 127.0.0.1 -p 5432 continua a funcionar no host. Numa stack pequena e corretamente configurada, apenas o reverse proxy publica portas, nas portas 80 e 443. Por que as portas publicadas pelo Docker ignoram o UFW explica a cadeia DOCKER-USER nos casos em que é necessário publicar uma porta e filtrá-la na mesma. Noções básicas da firewall UFW explica as regras do host subjacentes.

Por que os meus containers desaparecem depois de um reboot?

Porque nada lhes disse para voltarem a arrancar. Um container é criado com a política de reinício no se não definir outra, por isso um reboot deixa-o parado e o daemon não intervém. Os reboots não são raros numa VPS: atualizações do kernel através de unattended upgrades, manutenção do fornecedor e a sequência OOM acima terminam todos num deles.

Duas condições têm de ser cumpridas. O daemon tem de arrancar no boot:

systemctl is-enabled docker

Isto apresenta enabled numa instalação Ubuntu padrão. Depois, cada serviço precisa de uma política:

services:
  app:
    image: ghcr.io/example/app:1.4
    restart: unless-stopped

unless-stopped volta a arrancar o container depois de um reboot e respeita um container que parou de propósito. always também reinicia os containers que parou deliberadamente sempre que o daemon reinicia, o que pode ser inesperado durante a depuração. Editar o ficheiro não é suficiente, porque a política de reinício é definida quando o container é criado. Execute docker compose up -d para o recriar e, depois, confirme o valor ativo:

docker inspect my-app | grep -A3 RestartPolicy

Depois, faça reboot do servidor de propósito e execute docker compose ps no diretório do projeto. Uma stack que sobrevive a um reboot planeado também sobrevive a um reboot não planeado. Se a sua stack precisar de uma garantia de ordem ou de um job executado uma única vez no boot, uma unidade systemd é uma ferramenta melhor: iniciar Docker Compose no boot inclui o ficheiro da unidade. Para confirmar se um container que voltou a arrancar está efetivamente a servir pedidos, adicione healthchecks do Compose.

Por que o disco do meu VPS está cheio?

Porque o Docker mantém tudo até lhe indicar o contrário. Cada tag de imagem que alguma vez descarregou, cada contentor parado, cada volume anónimo deixado por uma recriação e cada camada da cache de compilação permanecem no disco. Num sistema de ficheiros root de 40 GB ou 80 GB, o que é normal nestas dimensões de plano, isso transforma-se numa interrupção do serviço em meses, e não em anos.

Um disco cheio não se manifesta como uma falha do sistema. Na mesma hora, recebe no space left on device de um contentor, de apt, do journald e de docker pull. O PostgreSQL deixa de aceitar escritas. O servidor continua ativo, o que torna o problema mais difícil de detetar do que um ciclo contínuo de reinícios.

Verifique antes de apagar:

docker system df
df -h /

docker system df divide o total entre imagens, contentores, volumes locais e cache de compilação, com uma coluna RECLAIMABLE junto de cada categoria. Num servidor que cria as próprias imagens, a cache de compilação costuma ser a maior categoria.

docker image prune -a
docker builder prune
docker system df

docker image prune -a remove todas as imagens que nenhum contentor está a utilizar. docker builder prune limpa a cache de compilação. Ambos são seguros enquanto os serviços estão em execução, porque os elementos em uso são ignorados. O que não é seguro é docker system prune --volumes, que elimina todos os volumes que nenhum contentor referencia neste momento. Uma stack que parou durante o fim de semana tem exatamente essa situação, e o respetivo volume da base de dados é eliminado. Leia diferenças entre bind mounts e volumes nomeados antes de utilizar essa flag e faça primeiro uma cópia de segurança.

Os logs dos contentores são uma fonte de crescimento mais discreta. O driver json-file predefinido não tem limite de tamanho, por isso um contentor com muitos logs pode escrever gigabytes em /var/lib/docker/containers. Defina um limite para todos os contentores em /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Aplique a alteração com sudo systemctl restart docker. Este comando reinicia os seus contentores, por isso escolha o momento adequado. O limite aplica-se aos contentores criados depois da alteração. Recrie os contentores em execução com docker compose up -d --force-recreate e confirme:

docker inspect my-app | grep -A5 LogConfig
sudo du -sh /var/lib/docker/containers

O resultado de inspect deve mostrar max-size definido. Se estiver vazio, esse contentor foi criado antes da alteração e continua a escrever sem limite.

Hábitos que mantêm um pequeno servidor Docker saudável

Nada disto exige um dashboard ou uma ferramenta que tenha de aprender.

  • Execute docker system df e df -h / no primeiro dia de cada mês. São dois comandos, demoram trinta segundos e permitem identificar a tendência muito antes de esta causar uma indisponibilidade.
  • Defina um limite de memória para todos os serviços, incluindo os que tem a certeza de serem pequenos. O limite transforma uma indisponibilidade de todo o host num único contentor reiniciado.
  • Monitorize o servidor a partir de outro local, para ser avisado da pressão sobre a memória ou o disco antes de o kernel atuar. O Uptime Kuma é executado num contentor e fica inativo com cerca de 95 MB.
  • Faça cópias de segurança dos volumes, não dos contentores. O contentor é descartável, mas o volume não. cópias de segurança restic num VPS abrange a definição de um agendamento e um teste de restauro.
  • Fixe as tags das imagens no ficheiro compose e atualize-as num dia escolhido por si. Com latest, a versão obtida no próximo docker compose pull é a que foi lançada nessa manhã.

Um VPS pequeno com Docker mantém-se saudável durante anos quando quatro valores permanecem dentro dos limites: o orçamento de memória, a lista de portas publicadas, a política de reinício de cada serviço e o espaço livre em disco. Tudo o resto é o mesmo Docker que já executa em casa.

FAQ

Quanta RAM preciso para executar o Docker numa VPS?

O Docker em si consome poucos recursos. O daemon e o containerd juntos ocupam cerca de 100 MB; o restante depende dos seus contentores. Reserve primeiro a parte do host: 768 MB numa máquina com 2048 MB para o sistema operativo, o daemon e alguma margem. Isso deixa 1280 MB para os contentores. Uma base de dados com 512 MB, um reverse proxy com 128 MB e duas aplicações pequenas cabem nesse limite. Meça a sua própria stack com docker stats --no-stream em vez de confiar em valores publicados.

Posso executar o Docker numa VPS com 1 GB?

Sim, para um ou dois contentores leves. Crie também um ficheiro de swap antes de começar. Cerca de metade de uma máquina com 1 GB fica ocupada depois de arrancarem o sistema operativo e o daemon do Docker. Sobra espaço para uma aplicação pequena e um reverse proxy, mas não para uma base de dados sob carga real. A criação de imagens numa máquina desse tamanho pode falhar ou terminar outro processo. Por isso, crie as imagens noutro local e faça pull da imagem final.

O UFW protege um contentor Docker?

Não protege as portas que publica. O Docker cria as suas próprias regras de DNAT e de encaminhamento. Assim, um pacote destinado a uma porta publicada do contentor é encaminhado para o contentor, em vez de ser entregue ao host. As regras INPUT geridas pelo UFW nunca o veem. ufw deny 5432 pode estar ativo enquanto essa porta responde a partir da internet. Publique a porta na loopback com 127.0.0.1:5432:5432, mantenha os serviços internos sem publicação ou filtre na cadeia DOCKER-USER.

Os meus contentores reiniciam depois de um reboot da VPS?

Só se tiverem sido criados com uma política de reinício. Defina restart: unless-stopped em cada serviço, execute docker compose up -d para recriar os contentores com essa política e confirme que systemctl is-enabled docker apresenta enabled. Depois, faça um reboot de propósito e verifique docker compose ps. Uma política de reinício que nunca foi testada não é uma política de reinício.

Com que frequência devo remover imagens do Docker?

Uma vez por mês é suficiente para a maioria dos servidores pequenos. Também pode fazê-lo quando docker system df indicar espaço recuperável que lhe faça falta. docker image prune -a e docker builder prune são seguros enquanto os serviços estão em execução, porque ignoram as imagens e a cache em uso. Evite docker system prune --volumes, a menos que saiba exatamente quais os volumes que não têm referências, porque o comando elimina os dados de qualquer stack que esteja parada.