UFW | Docker
- Como o UFW se relaciona com o Docker e qual o impacto disso | Docker

Visão geral
O ponto central é este: quando você publica portas com Docker, o tráfego pode passar por regras de NAT do Docker antes de cair nas regras que o UFW normalmente controla. Na prática, isso faz parecer que o UFW foi “ignorado”. A própria documentação do Docker diz que Docker e UFW são incompatíveis nesse fluxo porque o Docker desvia o tráfego na tabela nat antes de ele alcançar as chains INPUT e OUTPUT usadas pelo UFW. (Docker Documentation)
Além disso, a documentação atual de instalação do Docker no Ubuntu alerta explicitamente que, se você usa ufw ou firewalld, portas expostas pelo Docker podem contornar suas regras de firewall. Ela também orienta que, em sistemas com Docker, as regras compatíveis devem ser feitas com iptables/ip6tables e, quando necessário, aplicadas na chain DOCKER-USER. (Docker Documentation)
O que acontece por baixo dos panos
Quando você faz algo como:
docker run -d -p 8080:80 nginx
o Docker cria regras de iptables para fazer:
port-mappingmasqueradeforwardentre interfaces- aceitação de tráfego para containers publicados
O Docker cria chains próprias como:
DOCKER-USERDOCKER-FORWARDDOCKERDOCKER-INGRESSno caso de Swarm
e também adiciona regras na tabela nat para publicar portas. (Docker Documentation)
O problema com o UFW aparece porque ele normalmente trabalha no fluxo mais tradicional de INPUT/OUTPUT, enquanto o Docker intercepta e roteia esse tráfego antes. Resultado: você fecha uma porta no UFW, mas ela continua acessível porque foi publicada pelo Docker. (Docker Documentation)
Impacto prático
1. Porta publicada pode ficar acessível externamente mesmo com UFW “negando”
Exemplo:
sudo ufw deny 8080
docker run -d -p 8080:80 nginx
Mesmo com o deny, a porta pode responder externamente, porque a publicação do Docker ocorre fora do caminho esperado pelo UFW. Isso é exatamente o cenário que a documentação do Docker manda considerar como limitação de firewall. (Docker Documentation)
2. Sensação falsa de segurança
É comum o administrador pensar:
- “liberei só SSH no UFW”
- “então o resto está bloqueado”
Mas, se houver containers com -p ou ports: no Compose/Stack, essas portas podem estar expostas do mesmo jeito. Essa é uma das implicações de segurança mais relevantes no uso de Docker em Ubuntu/Debian com UFW. (Docker Documentation)
3. Swarm amplia a superfície de exposição
No Docker Swarm, além das portas publicadas dos serviços, o Docker também cria regras relacionadas a DOCKER-INGRESS para a rede de ingresso. Isso significa que o raciocínio “o UFW resolve sozinho” fica ainda mais perigoso em cluster. (Docker Documentation)
4. Regras no FORWARD podem não surtir efeito como você espera
O Docker injeta saltos automáticos no FORWARD para suas próprias chains. A documentação informa que regras adicionadas diretamente depois no FORWARD podem ser processadas tarde demais. Para filtrar corretamente o tráfego dos containers, o lugar indicado é a chain DOCKER-USER. (Docker Documentation)
Exemplo do problema
Cenário
Você tem um servidor Ubuntu com:
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
Até aqui, a expectativa é: só SSH aberto.
Agora sobe um container:
docker run -d --name app -p 9000:80 nginx
Efeito esperado por quem olha só o UFW:
- porta
9000deveria continuar fechada
Efeito real:
- porta
9000pode ficar acessível externamente por causa das regras criadas pelo Docker noiptables/nat. (Docker Documentation)
Como isso impacta arquitetura
Reverse proxy
Se você usa Nginx, Traefik, Kong, APISIX ou outro gateway, o ideal costuma ser:
- publicar externamente só as portas do proxy
- deixar os demais containers sem publicação direta
- comunicação interna via rede Docker
Isso reduz o risco de “furar” o firewall por acidente.
Exemplo melhor:
services:
proxy:
image: nginx
ports:
- "80:80"
- "443:443"
api:
image: minha-api
expose:
- "8080"
Aqui:
portspublica no hostexposeapenas documenta/exibe para rede interna do Docker, mas não publica no host
Esse comportamento está alinhado com o modelo de rede bridge e com a distinção entre porta exposta e porta publicada descrita na documentação e em materiais de Docker. (Docker Documentation)
Host networking
Se você usa network_mode: host ou rede host, o container compartilha diretamente a pilha de rede do host. Isso elimina o isolamento típico do bridge e exige ainda mais cuidado com firewall e binding de portas. A documentação e materiais de Docker tratam a rede host como mais direta e com menos isolamento. (Docker Documentation)
O que fazer na prática
1. Não publique porta sem necessidade
A primeira defesa é simples:
- não use
-pà toa - publique apenas o que realmente precisa sair para fora
- prefira rede interna Docker para banco, cache, fila, APIs internas
Exemplo:
docker run -d --name redis redis
Melhor do que:
docker run -d --name redis -p 6379:6379 redis
2. Faça filtros na chain DOCKER-USER
O Docker orienta usar DOCKER-USER para regras personalizadas, porque ela é processada antes das chains automáticas do Docker. (Docker Documentation)
Exemplo bloqueando acesso externo a uma porta publicada, exceto uma origem específica:
sudo iptables -I DOCKER-USER -p tcp --dport 9000 ! -s 10.0.0.10 -j DROP
Liberando uma sub-rede interna:
sudo iptables -I DOCKER-USER -p tcp --dport 9000 -s 10.0.0.0/24 -j ACCEPT
sudo iptables -A DOCKER-USER -p tcp --dport 9000 -j DROP
3. Faça bind em interface específica
Em vez de publicar para 0.0.0.0, publique só em loopback ou IP interno.
Exemplo local apenas:
docker run -d -p 127.0.0.1:9000:80 nginx
Exemplo em rede privada:
docker run -d -p 10.116.0.5:9000:80 nginx
Isso reduz muito a exposição acidental. É uma prática coerente com a recomendação de restringir conexões externas aos containers. (Docker Documentation)
4. Em Swarm, controle também as portas do cluster
No Swarm, pense em três grupos de portas:
- portas publicadas pelos serviços
- portas internas do cluster/ingress
- portas de gestão e overlay
O UFW sozinho não deve ser sua única camada de defesa para isso. Combine:
- binding correto
- segmentação de rede
- regras em
DOCKER-USER - publicação mínima
5. Não desligue iptables do Docker sem saber exatamente o que está fazendo
A documentação do Docker diz que desabilitar a manipulação de iptables/ip6tables não é recomendado para a maioria dos usuários, porque isso pode quebrar a rede dos containers. (Docker Documentation)
6. Atenção ao backend do firewall
A documentação atual informa que o Docker é compatível com:
iptables-nftiptables-legacy
e que regras criadas com nft puro não são suportadas nesse cenário. (Docker Documentation)
Boas práticas resumidas
- trate
ports:e-pcomo abertura real de porta no host - use UFW para política geral do host, mas não confie nele sozinho para portas publicadas pelo Docker
- aplique restrições específicas na
DOCKER-USER - publique portas só no proxy/gateway quando possível
- faça bind em
127.0.0.1ou IP interno quando a porta não for pública - revise serviços do Swarm com atenção extra
- evite expor banco, Redis, RabbitMQ e painéis administrativos diretamente
Comandos úteis para auditoria
Ver portas publicadas:
docker ps
Inspecionar mapeamento de portas:
docker inspect <container_id>
Ver regras Docker no iptables:
sudo iptables -S
sudo iptables -t nat -S
Ver chain importante para filtros manuais:
sudo iptables -S DOCKER-USER
Ver status do UFW:
sudo ufw status verbose
Regra mental correta
A forma certa de pensar é:
- UFW protege o host
- Docker altera o caminho do tráfego publicado
- porta publicada por Docker não deve ser tratada como “controlada automaticamente” pelo UFW
Em outras palavras: publicou com Docker, revise iptables/DOCKER-USER e não só o UFW. (Docker Documentation)