O UFW foi criado para que uma firewall se configurasse com três comandos, e nisso consegue. O problema está noutro sítio: o ufw status mostra intenções, não resultados. Uma regra pode constar da lista e não fechar absolutamente nada, por três motivos diferentes que em servidores reais aparecem com regularidade.

Um começo que não o deixa de fora

A ordem dos comandos importa. Primeiro permitir o SSH, depois ativar:

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

O ufw enable antes de permitir o SSH corta a sua própria sessão, e depois resta apenas a consola do alojamento. Se o servidor já está configurado e não tem a certeza, mantenha uma segunda ligação aberta: sobreviverá a uma alteração mal feita.

Veja o estado detalhado; o curto esconde a política por omissão:

sudo ufw status verbose

Erro um: a regra existe e a porta está aberta ao mundo

A linha mais frequente em configurações alheias:

sudo ufw allow 3306

É assim que se abre o MySQL «para poder ligar-me de casa», e abre-se a toda a internet. Há duas variantes corretas, e ambas são melhores:

sudo ufw allow from 203.0.113.25 to any port 3306

ou, ainda mais fiável, não deixar o serviço sair de todo: bind-address = 127.0.0.1 na configuração do MySQL e acesso externo por um túnel SSH. A firewall é a segunda linha; a primeira é o serviço não escutar num endereço público. Uma regra do UFW pode ser apagada por engano, o bind-address não muda sozinho.

Erro dois: IPv6

Uma regra do tipo ufw allow from 203.0.113.25 diz respeito apenas ao IPv4. Se o servidor tem endereço IPv6 — e a maioria dos VPS tem, ativo — o serviço continua acessível por ele. O alojamento atribuiu o endereço, você não se lembra dele, o verificador conhece-o.

Confirme que a filtragem v6 está ativa (IPV6=yes em /etc/default/ufw) e que o serviço não escuta em :: sem necessidade:

ss -tulpn | grep ':::'

As regras que indicam um endereço explícito têm de ser escritas separadamente para cada versão do protocolo.

Erro três: Docker

O mais irritante. O Docker publica portas escrevendo as suas próprias regras nas cadeias iptables antes daquelas onde o UFW escreve. Em consequência, um contentor iniciado com -p 5432:5432 está acessível a partir da internet mesmo que o UFW mostre Status: active e uma política deny incoming. A firewall não está partida: simplesmente nunca lhe chega a vez.

Isso não se corrige no UFW mas na forma como a porta é publicada:

ports:
  - "127.0.0.1:5432:5432"

A associação ao endereço local é a solução mais simples e fiável. Para fora deve olhar apenas o que serve realmente os visitantes: normalmente as portas 80 e 443 de um proxy inverso.

A ordem das regras

O UFW aplica a primeira regra que corresponde e para aí. Uma negação acrescentada depois de uma permissão não funcionará: nunca se chega a ela. Veja a numeração e insira no sítio certo:

sudo ufw status numbered
sudo ufw insert 1 deny from 198.51.100.0/24
sudo ufw delete 7

As regras apagam-se por número, mas os números deslocam-se depois de cada remoção: apague uma de cada vez e releia a lista de todas as vezes.

A verificação a partir de fora

Os comandos locais mostram o que está configurado. O que saiu de facto só se vê a partir de outra máquina:

nmap -Pn -p- 203.0.113.25
nc -zv 203.0.113.25 3306

Serve qualquer outro servidor ou o seu computador de casa. É a única verificação que não mente, e vale a pena depois de cada reconfiguração assinalável, sobretudo depois de instalar algo que «configura a rede sozinho»: Docker, painéis de gestão, VPN.

Os registos

Por omissão o UFW quase não escreve nada. Ativa-se assim:

sudo ufw logging low

As entradas vão para /var/log/ufw.log, mas só se no sistema existir o rsyslog. No Debian 12 e no Ubuntu 24.04 pode faltar, e então tudo vai para o diário do systemd:

sudo journalctl -k | grep -i '\[UFW'

Um /var/log/ufw.log vazio por si só não significa nada: veja primeiro no diário.

O que esperar de uma firewall

O UFW fecha o que não deve estar acessível. Não examina o conteúdo dos pedidos ao que está aberto: a porta 443 está aberta a todos, e o que chegar ao sítio chegará sem obstáculos. Esse é o trabalho de outras ferramentas: um WAF ao nível da aplicação, um IDS ao nível do tráfego. A tarefa da firewall é mais modesta e mais importante: que a lista de portas abertas coincida com aquilo que julga sobre ela. Como fica essa lista com as regras ativas numa página mostra-o a demonstração abaixo.