Docker e Docker Compose no Ubuntu Server: guia passo a passo
Instalar Docker com apt install docker.io traz uma versão desatualizada do repositório padrão do Ubuntu e nenhum dos plugins oficiais — nem Buildx, nem Compose v2. O método correto usa o repositório próprio da Docker Inc. e leva sete comandos até o primeiro container rodando. Este guia cobre a instalação completa no Ubuntu Server 24.04/26.04 LTS e as duas armadilhas que pegam quem já roda UFW ou firewalld no servidor.
Por que não usar o pacote docker.io do Ubuntu
O repositório universe do Ubuntu empacota o Docker Engine com atraso — às vezes meses atrás da versão estável — e não inclui o plugin docker-compose-plugin nem o docker-buildx-plugin na mesma origem, forçando a misturar fontes de pacote. Isso gera conflito de dependência quando o Docker lança correção de segurança. O repositório oficial resolve isso: uma única fonte, assinada com a chave GPG da Docker, com Engine, CLI, containerd e os dois plugins sempre em versões compatíveis entre si.
Pré-requisitos
Ubuntu Server 22.04, 24.04 ou 26.04 LTS, 64 bits, com acesso root ou sudo. Se o servidor já teve Docker instalado por outro caminho — docker.io, Snap, ou uma instalação antiga — remova antes para evitar conflito de binário:
sudo apt remove docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc
Não tem problema o comando avisar que nenhum pacote estava instalado — é o caminho normal em servidor novo.
Passo a passo
1. Adicionar o repositório oficial e a chave GPG
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
A chave fica em /etc/apt/keyrings, não no chaveiro global do apt — é o padrão atual do Debian/Ubuntu para pacotes de terceiros, evita que uma chave comprometida valide pacotes de outros repositórios.
2. Registrar a fonte do apt
sudo tee /etc/apt/sources.list.d/docker.sources <O trecho
$(. /etc/os-release && echo ...)detecta sozinho se o servidor é Noble (24.04), Resolute (26.04) ou Jammy (22.04) — não precisa editar o codinome manualmente, o que evita o erro clássico de colar o comando de um tutorial para outra versão do Ubuntu.3. Instalar Docker Engine, CLI, containerd e os plugins
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginIsso traz tudo: o daemon (
docker-ce), o cliente de linha de comando, o runtime de containers (containerd.io), o builder multi-plataforma e o Compose v2 — que hoje é subcomando (docker compose), não o binário Python separado (docker-compose) descontinuado em 2023.4. Confirmar que o serviço subiu
sudo systemctl status docker sudo docker run hello-worldSe o serviço não estiver ativo,
sudo systemctl start dockerresolve. O containerhello-worldbaixa uma imagem mínima, imprime uma confirmação e sai sozinho — é o teste padrão de que o daemon aceita conexões pelo socket Unix.5. Liberar um usuário sem sudo para rodar Docker
sudo usermod -aG docker $USER newgrp dockerPense duas vezes antes de rodar isso em servidor de produção multiusuário: pertencer ao grupo
dockerequivale a ter root na máquina, porque qualquer container pode montar/do host com-v /:/mnt. Em servidor de uso único isso é aceitável; em servidor compartilhado, prefira mantersudo dockerou configurar modo rootless.6. Corrigir o firewall antes de expor qualquer porta
Este é o passo que mais gente pula e mais gente lamenta depois. O Docker manipula as regras do
iptablesdiretamente para rotear tráfego de container — e faz isso antes das regras do UFW ou do firewalld na cadeia do kernel. Resultado prático: umdocker run -p 3306:3306 mysqlexpõe a porta 3306 para a internet mesmo comufw deny 3306ativo, porque o Docker insere a regra de NAT em um ponto que o UFW não enxerga.A correção oficial não é desativar o Docker de mexer no iptables — quebraria a rede de containers. É adicionar as regras de bloqueio na chain própria que o Docker respeita:
sudo iptables -I DOCKER-USER -i eth0 ! -s 10.0.0.0/8 -j DROPAjuste
eth0para a interface pública real e a faixa de IP liberada para a sua rede interna. Qualquer regra na chainDOCKER-USERé avaliada antes do roteamento do Docker — é o único ponto de controle confiável para portas de container. Vale lembrar também que o Docker só é compatível comiptables-legacyouiptables-nft; regras criadas só comnftpuro não são respeitadas pelo daemon.7. Subir o primeiro serviço com Docker Compose
mkdir ~/meu-servico && cd ~/meu-servico cat > docker-compose.yml <<'EOF' services: web: image: nginx:stable restart: unless-stopped ports: - "127.0.0.1:8080:80" EOF docker compose up -dRepare no
127.0.0.1:8080:80em vez de só8080:80: publicar amarrado ao loopback impede exposição direta à internet enquanto não houver proxy reverso com TLS na frente — a mesma lógica do passo 6, aplicada sem precisar mexer em firewall.restart: unless-stoppedgarante que o container volte sozinho depois de reboot ou crash do daemon, sem reiniciar o que você parou manualmente.Limitar o log dos containers
Por padrão, o driver
json-filedo Docker não tem limite de tamanho — um container barulhento pode encher o disco em produção sem aviso. Defina o limite globalmente em/etc/docker/daemon.json:{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } sudo systemctl restart dockerIsso mantém no máximo 30 MB de log por container (3 arquivos de 10 MB, rotacionados), aplicado a todo container criado depois da mudança.
Perguntas frequentes
Docker Compose "não é reconhecido" mesmo depois de instalado?
O comando mudou dedocker-compose(com hífen, binário separado) paradocker compose(subcomando, plugin). Scripts antigos precisam ser atualizados.Preciso do Docker Desktop no servidor?
Não. Docker Desktop é para máquina de desenvolvimento com interface gráfica. Em servidor Linux, o Docker Engine por linha de comando é o caminho — é o que este guia instala.Container exposto mesmo com UFW ativo — por quê?
Porque o Docker injeta regras de NAT antes da cadeia que o UFW controla. É o comportamento coberto no passo 6 — a correção é regra na chainDOCKER-USER, não desativar o roteamento do Docker.Docker e Podman fazem a mesma coisa?
Ambos rodam containers OCI, mas o Podman dispensa daemon central e roda rootless por padrão. O Docker tem ecossistema maior de imagens e integrações — para a maioria dos servidores em produção hoje, ainda é a escolha mais compatível.Como desinstalar tudo, se precisar?
sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginremove os pacotes;sudo rm -rf /var/lib/docker /var/lib/containerdapaga imagens, volumes e containers — sem volta.Conclusão
A instalação em si leva menos de cinco minutos; o que separa um servidor Docker seguro de um vulnerável é o passo 6. Antes de publicar qualquer porta com
-p, confirme que ela está na chainDOCKER-USERou amarrada ao loopback como no exemplo do Compose. Com isso resolvido, o próximo passo natural é colocar um proxy reverso na frente dos containers para TLS — o guia de Nginx com Let's Encrypt do PulseIT cobre exatamente essa etapa.