Pular para o conteúdo
blog.kristyan.dev
linux segurança ufw firewall ubuntu docker

Linux: UFW, Firewalls e Docker

Um guia técnico e prático sobre UFW no Linux: o que ele faz, o que ele não faz, como conversa com netfilter, iptables, nftables e por que Docker consegue bagunçar a festa.


Firewall em Linux costuma cair em dois extremos: ou vira um assunto místico cheio de chains, hooks, tabelas e regras com cara de encantamento medieval, ou vira um botão bonito escrito “ativar proteção”.

O UFW fica no meio desses dois mundos.

Ele não é o firewall em si. Ele não inventa uma camada mágica de segurança. Ele não transforma uma VPS largada na internet em uma fortaleza só porque você digitou sudo ufw enable. O que ele faz é mais simples, e justamente por isso mais útil: o UFW é uma interface amigável para administrar regras de firewall no Linux usando a infraestrutura do netfilter.

E isso importa.

Porque a maioria das pessoas não precisa começar escrevendo regras cruas de iptables ou nftables para bloquear meia dúzia de portas. Mas também não deveria tratar firewall como um amuleto. UFW é uma ferramenta boa quando você entende onde ela termina.

Antes do UFW, vem o netfilter

Para entender UFW sem cair em fantasia, primeiro é preciso separar as camadas.

No Linux, quem realmente participa do caminho dos pacotes no kernel é o netfilter. Ele fornece os pontos de integração usados para filtrar pacotes, fazer NAT, rastrear conexões e aplicar políticas de rede.

Por cima dele entram ferramentas de espaço de usuário. Historicamente, a mais famosa foi o iptables, que virou quase sinônimo de firewall Linux. Depois veio o nftables, criado para substituir a família iptables, ip6tables, arptables e ebtables com uma arquitetura mais moderna.

O UFW entra em outra camada: ele é um frontend. A própria documentação do Ubuntu descreve o UFW como uma ferramenta criada para facilitar a configuração do iptables e fornecer uma maneira amigável de criar um firewall baseado em host para IPv4 e IPv6.

Ou seja:

Camadas entre o UFW, os backends iptables ou nftables, o netfilter e o kernel Linux

O UFW simplifica a configuração, mas a filtragem de pacotes acontece sobre camadas mais baixas da pilha do Linux.

Essa separação evita muita confusão. Quando você usa UFW, você não está “fugindo” do firewall real do Linux. Você está usando uma interface mais simples para gerar e administrar regras que descem para a infraestrutura real.

É a diferença entre dirigir um carro automático e fingir que o motor não existe.

Um pouco de história: por que o UFW existe

O UFW apareceu no Ubuntu 8.04 LTS como uma tentativa bem pragmática de resolver um problema comum: iptables era poderoso, mas pouco amigável para configurações simples.

A wiki do Ubuntu descreve o UFW como um frontend para iptables, especialmente adequado para firewalls baseados em host. A ideia nunca foi substituir toda a flexibilidade de regras avançadas. A ideia foi dar uma interface previsível para casos comuns.

Esse detalhe é importante porque define a expectativa correta.

UFW não é uma linguagem completa de firewall. Ele é ótimo para responder perguntas simples e operacionais, como negar conexões de entrada por padrão, liberar SSH, permitir HTTP e HTTPS, limitar tentativas repetidas em uma porta ou bloquear um IP específico. Quando a pergunta vira “quero criar uma topologia complexa com múltiplas interfaces, NAT customizado, prioridades de chains e integração fina com containers”, talvez você esteja no território de nftables direto, firewalld ou regras específicas fora do UFW.

E tudo bem. Ferramenta boa não precisa resolver todos os problemas do planeta. Inclusive, quando tenta, geralmente vira Kubernetes.

Instalando e verificando o básico

No Ubuntu, o UFW normalmente já vem disponível, mas pode não estar ativo. Em distribuições derivadas de Debian, a instalação é direta:

sudo apt install ufw

No Arch Linux:

sudo pacman -S ufw

Antes de sair ativando qualquer coisa, veja o estado atual:

sudo ufw status verbose

Em uma instalação comum, o UFW pode aparecer como inativo. Isso não significa que o sistema está quebrado. Significa apenas que o frontend ainda não está aplicando a política dele.

Também vale entender qual backend de firewall o sistema está usando. Em muitas distribuições modernas, o comando iptables pode estar usando uma camada de compatibilidade sobre nftables:

sudo iptables -V

E, em sistemas baseados em Debian/Ubuntu, você pode inspecionar as alternativas:

sudo update-alternatives --display iptables

Isso ajuda a evitar uma confusão comum: achar que “iptables” sempre significa o backend antigo. Às vezes, você está chamando a sintaxe do iptables, mas por baixo o sistema está usando nftables.

A primeira regra: não se tranque fora da máquina

Se você está configurando UFW em uma máquina remota, principalmente uma VPS acessada por SSH, a regra de ouro é simples: libere SSH antes de ativar o firewall.

sudo ufw allow OpenSSH

Ou, se preferir explicitar a porta:

sudo ufw allow 22/tcp

Depois disso, ative:

sudo ufw enable

O próprio manual do UFW alerta para esse cenário: ativar o firewall pode derrubar conexões existentes, especialmente se a regra de SSH não estiver liberada. O UFW costuma avisar quando detecta uma sessão SSH, mas aviso não é backup, não é console serial e não é plano de recuperação.

Em servidor remoto, firewall sem plano de acesso alternativo é só um jeito sofisticado de criar um ticket para você mesmo.

Políticas padrão: a base de quase tudo

Uma configuração comum e sensata para máquina pessoal, servidor simples ou VPS é negar entrada, permitir saída e negar roteamento por padrão:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

Na prática, isso significa que conexões novas vindas de fora serão bloqueadas, salvo exceções explícitas; conexões iniciadas pela própria máquina poderão sair; e tráfego roteado pela máquina será negado por padrão. Esse modelo funciona bem para a maioria dos hosts. Ele reduz superfície exposta sem transformar a máquina em uma ilha sem internet.

Fluxo das políticas padrão do UFW: negar entrada, permitir saída e negar tráfego roteado

A política padrão define o comportamento geral; as regras allow abrem apenas os serviços necessários.

Depois você libera apenas o que precisa.

Liberando serviços comuns

Para um servidor web:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Para SSH:

sudo ufw allow OpenSSH

Para PostgreSQL apenas a partir de uma rede interna específica:

sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcp

Para bloquear um IP específico:

sudo ufw deny from 203.0.113.10

Para permitir acesso a uma porta apenas de um IP:

sudo ufw allow from 203.0.113.20 to any port 22 proto tcp

Essa sintaxe é justamente o motivo pelo qual o UFW é popular. Ela é legível. Dá para entender a regra seis meses depois, o que é uma qualidade subestimada em configuração de infraestrutura.

Perfis de aplicação

O UFW também suporta perfis de aplicação. Eles ficam normalmente em /etc/ufw/applications.d e permitem liberar serviços por nome.

Para listar os perfis disponíveis:

sudo ufw app list

Para ver detalhes de um perfil:

sudo ufw app info OpenSSH

Para permitir um perfil:

sudo ufw allow OpenSSH

Isso é útil quando pacotes instalam perfis próprios. Mas também tem uma pegadinha: perfil de aplicação não é auditoria de segurança. Antes de confiar em um nome bonito, veja quais portas ele realmente libera.

Regra por número, regra por conteúdo e pequenas armadilhas

Para ver as regras numeradas:

sudo ufw status numbered

Para remover uma regra pelo número:

sudo ufw delete 3

Também é possível remover pela própria regra original:

sudo ufw delete allow 80/tcp

A remoção por número é prática, mas exige atenção. Depois que você apaga uma regra, a numeração muda. Apagar várias regras em sequência olhando uma lista antiga é um convite para remover a regra errada.

Outro detalhe importante envolve IPv6. A documentação do Ubuntu lembra que o UFW pode criar regras para IPv4 e IPv6. Em alguns casos, remover por número pode remover apenas uma das variantes. Remover pela regra original tende a ser mais claro quando a intenção é apagar a regra completa.

IPv6 não é opcional só porque você esqueceu dele

Muita gente configura firewall pensando apenas em IPv4 e esquece que a máquina também pode estar exposta em IPv6.

No UFW, o suporte a IPv6 depende da configuração em:

/etc/default/ufw

Procure por:

IPV6=yes

Depois de alterar isso, é comum precisar recarregar o UFW:

sudo ufw reload

A moral aqui é simples: se sua máquina tem IPv6 público e seu firewall só foi pensado em IPv4, você não tem um firewall completo. Você tem uma esperança.

Logs: úteis, mas não mágicos

O UFW permite ajustar o nível de log:

sudo ufw logging on

Também existem níveis como low, medium, high e full, conforme descrito no manual do UFW.

Para acompanhar logs em sistemas com journal:

sudo journalctl -u ufw

Ou, dependendo da distribuição e configuração:

sudo tail -f /var/log/ufw.log

Logs ajudam a entender o que está sendo bloqueado, mas não substituem monitoramento, IDS, revisão de serviços expostos ou configuração correta da aplicação. Firewall é uma camada. Não é uma licença para rodar serviço vulnerável de 2014 exposto na internet.

Testando sem autoengano

Ver o status do UFW é útil:

sudo ufw status verbose

Mas isso mostra a configuração do firewall, não necessariamente tudo que está exposto como você imagina.

Veja quais serviços estão escutando:

sudo ss -tulpen

Teste uma porta localmente:

nc -vz 127.0.0.1 5432

Teste de outra máquina na rede:

nc -vz 192.168.1.50 5432

E, quando fizer sentido, use um scanner a partir de fora:

nmap -Pn -p 1-1000 seu-servidor.example.com

O teste externo é importante porque firewall, NAT, Docker, provedor cloud e bind da aplicação podem produzir resultados diferentes do que você acha olhando apenas para o host.

O comando limit e o mito do anti-bruteforce mágico

O UFW tem uma ação chamada limit:

sudo ufw limit OpenSSH

Ela limita tentativas repetidas de conexão a partir do mesmo IP. Segundo o manual, o UFW normalmente nega conexões quando um IP inicia seis ou mais conexões em trinta segundos.

Isso ajuda contra ruído e tentativas simples de brute force. Mas não substitui autenticação por chave, desabilitar login por senha quando possível, usar usuários não óbvios, manter o OpenSSH atualizado e monitorar tentativas suspeitas.

ufw limit é um freio. Não é uma muralha.

UFW em desktop Linux

Em desktop, uma configuração simples costuma ser suficiente:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable

Isso bloqueia conexões novas chegando de fora, mas permite que seu navegador, gerenciador de pacotes, cliente Git e outros programas acessem a rede normalmente.

Para a maioria dos desktops, isso já reduz bastante exposição acidental. Serviços de desenvolvimento, servidores locais e ferramentas que abrem portas deixam de ficar acessíveis por qualquer máquina na mesma rede sem que você perceba.

Mas vale uma observação: UFW não é um firewall interativo de aplicação no estilo “o Firefox pode acessar a internet?” ou “este binário desconhecido pode fazer conexão externa?”. Para esse tipo de controle, ferramentas como o OpenSnitch fazem mais sentido.

UFW em servidor

Em servidor, o raciocínio precisa ser mais explícito: tudo começa fechado, e só o necessário abre.

Exemplo para um servidor web comum:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable
sudo ufw status verbose

Se o banco de dados roda no mesmo host, ele provavelmente não precisa estar exposto na rede. Configure a aplicação para acessar via localhost ou socket Unix, e confirme que o banco não está escutando em 0.0.0.0 sem necessidade.

Se o banco precisa ser acessado por outro host, restrinja por IP ou rede:

sudo ufw allow from 10.0.0.0/24 to any port 5432 proto tcp

Essa é a diferença entre “funciona” e “funciona sem gritar seu banco para a internet”.

UFW, Docker e a festa que acaba em IPTables

Agora vem a parte em que o UFW deixa de parecer tão simples.

Docker altera regras de firewall para implementar redes bridge, isolamento entre containers, NAT e publicação de portas. A documentação oficial do Docker explica que o Docker cria regras de firewall para redes bridge e, por padrão, usa iptables para isso. Também há suporte a nftables via backend próprio em versões recentes, mas isso não elimina a necessidade de entender a interação com o firewall do host.

O problema clássico: Docker e UFW podem não se comportar como você espera.

A própria documentação do Docker afirma que Docker e UFW são incompatíveis no sentido de que o tráfego de portas publicadas pode ser desviado antes de passar pelas chains INPUT e OUTPUT que o UFW usa. Resultado: uma porta publicada por container pode ficar acessível mesmo que sua configuração mental do UFW diga o contrário.

Exemplo perigoso:

docker run -p 8080:80 nginx

Isso publica a porta em todas as interfaces por padrão. Em uma VPS, pode significar internet inteira.

Uma alternativa mais segura para desenvolvimento local é bindar explicitamente no loopback:

docker run -p 127.0.0.1:8080:80 nginx

No Docker Compose:

services:
  web:
    image: nginx
    ports:
      - "127.0.0.1:8080:80"

Esse detalhe vale ouro. Se o serviço só precisa existir localmente atrás de um proxy reverso, túnel ou ambiente de desenvolvimento, não publique em 0.0.0.0 por preguiça.

Comparação entre uma porta Docker publicada em todas as interfaces e uma porta restrita ao loopback local

Em hosts com Docker, a forma de publicar a porta pode ser mais decisiva do que a regra UFW que você imaginava estar protegendo tudo.

“Então UFW não funciona com Docker?”

Funciona, mas com ressalvas.

O ponto é não assumir que uma regra UFW bloqueando entrada vai necessariamente controlar tudo que o Docker publica. Docker mexe na pilha de firewall para fazer o container funcionar, e isso pode passar por caminhos diferentes dos que você está olhando.

A documentação do Docker recomenda cautela ao desabilitar a manipulação de regras por iptables, porque isso pode quebrar a rede dos containers. Ou seja, a solução também não é sair colocando iptables: false como se fosse tempero.

Em ambientes com Docker, algumas práticas ajudam bastante. Publique portas apenas em 127.0.0.1 quando elas não precisarem ser públicas, use um proxy reverso como ponto único de entrada, revise as portas publicadas com docker ps, teste de fora da máquina e entenda se o daemon está usando backend iptables ou nftables. Acima de tudo, trate firewall de container como parte da arquitetura, não como detalhe esquecido depois do deploy.

O Docker também documenta o backend experimental/alternativo com nftables e explica que, nesse modo, ele cria tabelas próprias como ip docker-bridges e ip6 docker-bridges. A recomendação é não modificar diretamente as tabelas do Docker, mas criar tabelas separadas quando precisar de regras próprias.

Firewall com container não é impossível. Só deixa de ser “UFW allow 443 e fé”.

UFW route: quando a máquina também encaminha tráfego

O UFW também tem regras para tráfego roteado:

sudo ufw route allow in on eth1 out on eth0

Esse tipo de regra importa quando a máquina atua como roteador, gateway, VPN server, host de containers ou qualquer coisa que encaminhe pacotes entre interfaces.

Mas não basta escrever uma regra ufw route. O encaminhamento de IP precisa estar habilitado no sistema. O próprio manual aponta configurações em /etc/ufw/sysctl.conf, como:

net/ipv4/ip_forward=1

Em IPv6, há configuração equivalente.

Esse é outro bom exemplo de limite do UFW: ele administra regras, mas o comportamento final depende também de sysctl, interfaces, rotas e serviços em volta.

Comparando UFW, iptables, nftables, firewalld e OpenSnitch

UFW é uma boa escolha quando você quer uma política host-based simples, legível e fácil de manter.

iptables puro dá controle mais baixo nível, mas cobra em legibilidade e manutenção. Para muitos casos, é mais poder do que necessidade.

nftables é o caminho moderno e mais expressivo para regras avançadas no Linux. Ele substitui a família antiga de ferramentas e oferece uma base mais consistente. Mas escrever nftables direto exige mais entendimento da pilha.

firewalld é uma alternativa interessante quando você quer um modelo dinâmico baseado em zonas e políticas. A documentação do firewalld descreve a ferramenta como um firewall stateful baseado em zonas, com separação entre configuração runtime e permanente. Ele costuma aparecer bastante em Fedora, RHEL e derivados.

OpenSnitch joga outro jogo: controle interativo por aplicação, especialmente para tráfego de saída em desktop Linux. É mais próximo de um “Little Snitch para Linux” do que de um substituto direto para UFW em servidor.

A escolha honesta depende do problema. Para um firewall simples de host, UFW costuma ser o caminho mais direto. Para controle avançado e moderno, nftables merece mais atenção. Em ecossistemas RHEL, Fedora e derivados, firewalld conversa melhor com o modelo de zonas. Para controlar conexões por aplicação em desktop, OpenSnitch joga melhor esse jogo. E, quando o assunto é legado, manutenção de ambiente antigo ou sofrimento por nostalgia, iptables direto ainda aparece bastante.

Brincadeiras à parte, iptables ainda está em muito lugar e entender sua lógica continua útil. Mas para configuração nova e avançada, nftables merece atenção.

Um fluxo prático para configurar UFW sem drama

Em uma máquina nova, eu gosto de seguir uma ordem simples.

Primeiro, ver o estado:

sudo ufw status verbose

Depois, definir políticas padrão:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw default deny routed

Se for servidor remoto, liberar SSH antes de ativar:

sudo ufw allow OpenSSH

Adicionar os serviços realmente necessários:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Ativar:

sudo ufw enable

Verificar:

sudo ufw status numbered
sudo ss -tulpen

Testar de fora.

E documentar o motivo das portas abertas. Firewall sem documentação vira arqueologia. Você encontra uma porta liberada daqui a dois anos e ninguém sabe se era uma necessidade real, um teste esquecido ou um ritual antigo para agradar algum deploy.

O que o UFW não resolve

UFW não corrige serviço vulnerável, não substitui atualização de pacote, não faz hardening de SSH sozinho e não entende automaticamente sua arquitetura Docker. Ele também não impede vazamento se você libera a porta errada para o mundo, nem substitui autenticação, criptografia, segregação de rede, backup, monitoramento e bom senso.

Isso não diminui a ferramenta. Pelo contrário. Saber o que uma ferramenta não faz é uma das formas mais saudáveis de usá-la bem.

Conclusão

UFW é uma das melhores portas de entrada para firewall em Linux porque ele reduz a fricção sem esconder completamente o modelo mental.

Ele permite criar uma política segura o suficiente para muitos hosts com poucos comandos, mas ainda obriga você a pensar em portas, protocolos, origem, destino e direção do tráfego. Isso é bom. Segurança que elimina completamente o pensamento geralmente só está escondendo a complexidade em outro lugar.

O melhor uso do UFW é pragmático: negar entrada por padrão, liberar o mínimo necessário, testar de fora, prestar atenção em IPv6, entender a interação com Docker e não fingir que uma camada resolve todos os problemas.

No fim, UFW não é um firewall mágico.

É só uma interface simples para uma parte importante do Linux.

E, honestamente, no mundo de infraestrutura, “simples e previsível” já é quase um superpoder.