Introdução: Por Que o nftables é Essencial em 2026
Se você administra servidores Linux expostos à internet, já sabe que firewall não é opcional — é literalmente a primeira barreira entre o seu servidor e um mundo de ameaças que só cresce. E os números de 2025 não mentem: 89% dos ataques contra endpoints Linux foram tentativas de força bruta, webshells representaram 49,6% de todo o malware Linux detectado, e o kernel Linux acumulou 5.530 CVEs em 2025, um salto de 28% em relação ao ano anterior. Botnets como P2PInfect e Tsunami varrem a internet 24/7, procurando servidores com configurações fracas.
Assustador, né?
Nesse cenário, o hardening firewall linux nftables deixou de ser coisa de "admin paranóico" e virou requisito básico. O nftables já é o framework de firewall padrão nas grandes distribuições: Debian 10+, Ubuntu 20.04+, RHEL 8+ e Fedora já migraram completamente. O iptables clássico tá oficialmente deprecated e só sobrevive pela camada de compatibilidade iptables-nft.
O kernel Linux 6.19.5, lançado em fevereiro de 2026, trouxe melhorias de desempenho bem relevantes para o nftables — incluindo a flag abort_skip_removal pro backend de conjuntos pipapo, que otimiza operações de remoção em conjuntos grandes. E o Docker 29.0.0 adicionou suporte experimental ao backend nftables, o que elimina uma das últimas barreiras pra adoção completa.
Neste guia, vou te mostrar passo a passo como fazer o hardening de firewall com nftables — desde a arquitetura básica até configurações avançadas com rate limiting dinâmico, integração com Fail2Ban, regras pra containers Docker, logging e monitoramento. Tudo testado e pronto pra produção.
Entendendo a Arquitetura do nftables
Antes de sair configurando regras, vale entender como o nftables organiza o processamento de pacotes. A arquitetura é baseada em três elementos: tabelas, chains e regras.
Tabelas
Uma tabela é basicamente um container de nível superior que agrupa chains e regras. Cada tabela pertence a uma família de endereços:
- ip — Apenas tráfego IPv4
- ip6 — Apenas tráfego IPv6
- inet — IPv4 e IPv6 simultaneamente (essa é a que você vai querer usar na maioria dos casos)
- arp — Tráfego ARP
- bridge — Tráfego de bridge
- netdev — Processamento no nível mais baixo, direto na interface de rede (ideal pra mitigação de DDoS)
A família inet é a mais usada em servidores modernos. O motivo é simples: ela permite criar um único conjunto de regras que se aplica tanto a IPv4 quanto a IPv6, sem precisar manter duas configurações separadas. Menos trabalho, menos chance de erro.
Chains
As chains são os pontos de processamento dentro de uma tabela. Uma diferença importante em relação ao iptables: enquanto o iptables já vinha com chains predefinidas (INPUT, OUTPUT, FORWARD), o nftables começa vazio — você cria exatamente o que precisa. As chains base se conectam aos hooks do netfilter no kernel:
- input — Pacotes destinados ao próprio host
- output — Pacotes originados do próprio host
- forward — Pacotes que atravessam o host (roteamento)
- prerouting — Pacotes antes da decisão de roteamento
- postrouting — Pacotes após a decisão de roteamento
Regras e Sets
As regras definem critérios de filtragem e ações (accept, drop, reject, log). Já os sets são coleções de valores — IPs, portas, intervalos — que permitem correspondência eficiente em tempo O(1) usando hash tables. No iptables, pra conseguir algo parecido, você precisava do pacote externo ipset.
Comparação entre nftables e iptables
| Característica | iptables | nftables |
|---|---|---|
| Ferramenta CLI | iptables, ip6tables, arptables, ebtables | Apenas nft |
| Dual-stack IPv4/IPv6 | Requer configurações separadas | Família inet unificada |
| Chains predefinidas | Sim (INPUT, OUTPUT, FORWARD) | Não — criadas pelo administrador |
| Sets nativos | Necessita ipset externo |
Integrado nativamente |
| Desempenho de correspondência | Busca linear O(n) | Hash sets O(1) |
| Atualizações atômicas | Não garantidas | Sim — carregamento atômico completo |
| Disponível desde | Kernel 2.4 (2001) | Kernel 3.13 (2014) |
| Status atual | Deprecated (mantido via iptables-nft) | Framework padrão ativo |
Instalação e Configuração Inicial
Instalação em Debian/Ubuntu
Na maioria das distribuições modernas, o nftables já vem pré-instalado. Mas caso não esteja, a instalação é bem direta:
# Debian / Ubuntu
sudo apt update && sudo apt install nftables
# Verificar a versão instalada
nft --version
# Saída esperada: nftables v1.1.1 (Broken Sword) ou superior
Instalação em RHEL/Fedora
# RHEL 8+ / Fedora / AlmaLinux / Rocky Linux
sudo dnf install nftables
# No RHEL/CentOS, desative o firewalld se for usar nftables diretamente
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl mask firewalld
Habilitando o Serviço
# Habilitar e iniciar o serviço nftables
sudo systemctl enable nftables
sudo systemctl start nftables
# Verificar o status
sudo systemctl status nftables
Política Default Deny
O princípio mais importante de qualquer firewall seguro é a política default deny: bloquear tudo por padrão e permitir apenas o tráfego explicitamente autorizado. Parece óbvio, mas você ficaria surpreso com quantos servidores em produção ainda usam policy accept. Enfim, aqui vai a configuração mínima:
#!/usr/sbin/nft -f
# Limpar todo o ruleset existente
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Tudo é bloqueado por padrão
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
# Tráfego de saída permitido por padrão
}
}
Atenção importante: se você aplicar essa configuração num servidor remoto via SSH, vai perder a conexão na hora. Sempre inclua regras pra tráfego estabelecido e SSH antes de aplicar a política drop. Eu já cometi esse erro uma vez — e posso garantir que a caminhada até o datacenter não foi agradável.
Configuração Completa de Firewall para Servidor
Agora vamos ao que interessa. Abaixo tá um ruleset completo pra um servidor de produção rodando serviços web. Ele usa a família inet pra cobertura dual-stack IPv4/IPv6 e inclui todas as regras essenciais com comentários explicativos:
#!/usr/sbin/nft -f
# ==============================================
# Hardening Firewall Linux com nftables
# Configuração para servidor web em produção
# ==============================================
flush ruleset
table inet filter {
# ---- CHAIN: INPUT ----
chain input {
type filter hook input priority 0; policy drop;
# 1. Permitir tráfego na interface loopback
iif "lo" accept comment "Permitir loopback"
# 2. Bloquear pacotes inválidos
ct state invalid drop comment "Descartar pacotes inválidos"
# 3. Permitir conexões estabelecidas e relacionadas
ct state { established, related } accept \
comment "Permitir conexões já estabelecidas"
# 4. ICMP com rate limiting (ping, path MTU discovery)
ip protocol icmp icmp type {
echo-request,
destination-unreachable,
time-exceeded
} limit rate 10/second accept \
comment "ICMPv4 com rate limiting"
# 5. ICMPv6 essencial (necessário para IPv6 funcionar)
ip6 nexthdr icmpv6 icmpv6 type {
echo-request,
destination-unreachable,
packet-too-big,
time-exceeded,
nd-neighbor-solicit,
nd-neighbor-advert,
nd-router-solicit,
nd-router-advert
} limit rate 10/second accept \
comment "ICMPv6 essencial com rate limiting"
# 6. SSH (porta 22) — limitado a 4 conexões novas por minuto
tcp dport 22 ct state new limit rate 4/minute accept \
comment "SSH com rate limiting"
# 7. HTTP e HTTPS
tcp dport { 80, 443 } accept \
comment "Permitir HTTP e HTTPS"
# 8. DNS (descomente se este servidor for resolver DNS)
# tcp dport 53 accept comment "DNS TCP"
# udp dport 53 accept comment "DNS UDP"
# 9. Logging de pacotes descartados (limitado para não lotar logs)
limit rate 5/minute burst 10 packets \
log prefix "[nftables-drop-input] " \
comment "Log de pacotes descartados"
}
# ---- CHAIN: FORWARD ----
chain forward {
type filter hook forward priority 0; policy drop;
# Nenhum encaminhamento permitido em servidor standalone
}
# ---- CHAIN: OUTPUT ----
chain output {
type filter hook output priority 0; policy accept;
# Todo tráfego de saída é permitido
}
}
Pra aplicar essa configuração, salve o conteúdo em /etc/nftables.conf e execute:
# Aplicar a configuração
sudo nft -f /etc/nftables.conf
# Verificar se as regras foram carregadas corretamente
sudo nft list ruleset
# Reiniciar o serviço para confirmar persistência
sudo systemctl restart nftables
Explicação das Regras Principais
- Interface loopback: sempre necessária pra comunicação interna entre processos no mesmo host. Por exemplo, sua aplicação conectando ao banco de dados local.
- Pacotes inválidos: são pacotes com flags TCP incoerentes ou que não pertencem a nenhuma conexão rastreada. Descartá-los elimina vetores de fingerprinting e ataques de evasão.
- Conexões estabelecidas: permite que respostas de conexões já iniciadas retornem ao servidor. Sem essa regra, nenhuma comunicação de saída vai funcionar direito.
- ICMP limitado: permite ping e descoberta de MTU, mas limita a 10 pacotes por segundo pra prevenir ICMP flood.
- SSH com rate limiting: limita novas conexões SSH a 4 por minuto por regra global. Não vai parar um atacante determinado sozinho, mas já dificulta bastante ataques de força bruta automatizados.
Proteção contra Força Bruta com Rate Limiting
O rate limiting básico por regra que mostrei acima é um bom começo, mas, sendo honesto, pra uma defesa realmente eficaz contra força bruta a gente precisa ir além. A solução são sets dinâmicos com timeout — eles rastreiam tentativas por IP individual e bloqueiam automaticamente endereços abusivos.
Sets Dinâmicos com Timeout Automático
A abordagem a seguir usa meters (sets dinâmicos) do nftables pra implementar rate limiting per-IP e blocklists com expiração automática. O melhor de tudo? Funciona sem depender de ferramentas externas:
#!/usr/sbin/nft -f
flush ruleset
table inet firewall {
# Set dinâmico para IPs bloqueados (expira após 30 minutos)
set bloqueados_ssh {
type ipv4_addr
flags dynamic, timeout
timeout 30m
}
# Set dinâmico para IPv6 bloqueados
set bloqueados_ssh_v6 {
type ipv6_addr
flags dynamic, timeout
timeout 30m
}
chain input {
type filter hook input priority 0; policy drop;
# Regras básicas
iif "lo" accept
ct state invalid drop
ct state { established, related } accept
# 1. Verificar se o IP já está na blocklist
ip saddr @bloqueados_ssh drop \
comment "Descartar IPs bloqueados IPv4"
ip6 saddr @bloqueados_ssh_v6 drop \
comment "Descartar IPs bloqueados IPv6"
# 2. Rate limiting per-IP para SSH:
# Mais de 4 tentativas em 60 segundos = bloqueio por 30 minutos
tcp dport 22 ct state new \
meter ssh_meter_v4 { ip saddr limit rate over 4/minute } \
add @bloqueados_ssh { ip saddr } \
log prefix "[nft-ssh-blocked] " \
drop \
comment "Bloquear SSH brute force IPv4"
tcp dport 22 ct state new \
meter ssh_meter_v6 { ip6 saddr limit rate over 4/minute } \
add @bloqueados_ssh_v6 { ip6 saddr } \
log prefix "[nft-ssh-blocked-v6] " \
drop \
comment "Bloquear SSH brute force IPv6"
# 3. Se passou no rate limiting, aceitar a conexão SSH
tcp dport 22 ct state new accept \
comment "Aceitar SSH dentro do limite"
# HTTP/HTTPS
tcp dport { 80, 443 } accept
# ICMPv4
ip protocol icmp icmp type {
echo-request,
destination-unreachable,
time-exceeded
} limit rate 10/second accept
# ICMPv6
ip6 nexthdr icmpv6 icmpv6 type {
echo-request,
destination-unreachable,
packet-too-big,
time-exceeded,
nd-neighbor-solicit,
nd-neighbor-advert
} limit rate 10/second accept
# Log de pacotes rejeitados
limit rate 5/minute log prefix "[nft-drop] "
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Verificando os Sets Dinâmicos
Pra monitorar quais IPs foram bloqueados automaticamente, use esses comandos:
# Listar IPs atualmente bloqueados
sudo nft list set inet firewall bloqueados_ssh
# Saída de exemplo:
# table inet firewall {
# set bloqueados_ssh {
# type ipv4_addr
# flags dynamic,timeout
# timeout 30m
# elements = { 192.168.1.100 timeout 30m expires 24m32s,
# 10.0.0.55 timeout 30m expires 18m15s }
# }
# }
# Remover um IP específico manualmente (falso positivo)
sudo nft delete element inet firewall bloqueados_ssh { 192.168.1.100 }
# Listar o meter para ver contadores
sudo nft list meter inet firewall ssh_meter_v4
Essa abordagem é extremamente eficiente porque todo o processamento acontece no kernel, sem nenhum processo em user space analisando logs. Pra maioria dos servidores, essa proteção nativa já é suficiente. Porém, se você precisa de coisas como tempos de bloqueio diferentes por serviço, integração com notificações ou regras mais elaboradas, o Fail2Ban ainda tem seu lugar.
Integração com Fail2Ban
O Fail2Ban monitora logs de serviços e bloqueia automaticamente IPs com comportamento suspeito. Desde a versão 0.9.4+, ele suporta nftables nativamente como backend de banimento. Vamos ver como configurar tudo.
Passo 1: Criar a Tabela do Fail2Ban
Primeiro, crie uma tabela dedicada pro Fail2Ban no nftables. Manter as regras de banimento separadas das regras manuais é uma boa prática — facilita a manutenção e evita confusão:
# Criar a tabela que o Fail2Ban usará
sudo nft add table inet f2b-table
sudo nft add chain inet f2b-table f2b-chain '{ type filter hook input priority -1; }'
Passo 2: Configurar o jail.local
Edite o arquivo /etc/fail2ban/jail.local pra usar o backend nftables:
# /etc/fail2ban/jail.local
[DEFAULT]
# Usar nftables como ação de banimento
banaction = nftables-multiport
banaction_allports = nftables-allports
# Tempo de banimento padrão: 1 hora
bantime = 3600
# Janela de observação: 10 minutos
findtime = 600
# Tentativas máximas antes do banimento
maxretry = 5
# Backend para monitoramento de logs
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
bantime = 7200
findtime = 300
[recidive]
enabled = true
banaction = nftables-allports
logpath = /var/log/fail2ban.log
bantime = 604800
findtime = 86400
maxretry = 3
Passo 3: Configurar a Ação nftables
O Fail2Ban já traz a ação nftables-multiport por padrão. Vale conferir se o arquivo de ação tá correto em /etc/fail2ban/action.d/nftables-multiport.conf:
# Verificar o conteúdo da ação padrão
cat /etc/fail2ban/action.d/nftables-multiport.conf
# Os parâmetros principais que devem estar configurados:
# [Definition]
# type = multiport
# nftables_family = inet
# nftables_table = f2b-table
Passo 4: Vincular com Systemd
Pra garantir que o Fail2Ban inicie depois do nftables (e que as tabelas já existam quando ele subir):
# Criar override do systemd para o Fail2Ban
sudo systemctl edit fail2ban
# Adicionar as seguintes linhas:
# [Unit]
# Requires=nftables.service
# After=nftables.service
# Recarregar o systemd e reiniciar os serviços
sudo systemctl daemon-reload
sudo systemctl restart nftables
sudo systemctl restart fail2ban
# Verificar o status
sudo fail2ban-client status
sudo fail2ban-client status sshd
Passo 5: O Jail Recidive
O jail recidive é uma daquelas camadas extras de proteção que fazem toda a diferença. Ele monitora o próprio log do Fail2Ban e bane por uma semana inteira qualquer IP que tenha sido banido 3 ou mais vezes em 24 horas. Funciona muito bem contra botnets que distribuem ataques ao longo do tempo, tentando voar abaixo do radar.
# Verificar IPs banidos pelo recidive
sudo fail2ban-client status recidive
# Verificar as regras criadas pelo Fail2Ban no nftables
sudo nft list table inet f2b-table
Firewall para Containers Docker
Ah, Docker e firewalls. Essa é uma daquelas combinações que já tirou o sono de muito administrador de sistemas (inclusive o meu). O problema é bem conhecido: o Docker manipula diretamente as regras do iptables pra configurar NAT e encaminhamento de pacotes, e frequentemente passa por cima ou ignora as regras do firewall que você configurou manualmente.
O Problema do Docker com iptables
Quando você publica uma porta com docker run -p 8080:80, o Docker cria regras de DNAT na chain PREROUTING e regras de FORWARD que aceitam tráfego diretamente — mesmo que suas regras de firewall na chain INPUT bloqueiem aquela porta. Ou seja, um container com porta publicada fica acessível externamente independente do que seu firewall diz.
Sim, é tão grave quanto parece.
Docker 29+ com Backend nftables
O Docker 29.0.0 finalmente trouxe suporte experimental ao backend nftables — algo que a comunidade esperava há anos. Pra habilitar:
# /etc/docker/daemon.json
{
"iptables": false,
"ip6tables": false,
"experimental": true,
"features": {
"nftables": true
}
}
# Reiniciar o Docker após a configuração
sudo systemctl restart docker
# Verificar as tabelas criadas pelo Docker
sudo nft list tables
# Deve mostrar uma tabela como: table ip docker
Regras Customizadas com DOCKER-USER Equivalente
Mesmo com o backend nftables, é importante criar regras que filtrem o tráfego antes que ele chegue às chains do Docker. No iptables existia a chain DOCKER-USER; no nftables, a gente cria uma chain de forward com prioridade mais alta:
#!/usr/sbin/nft -f
# Tabela para regras customizadas de Docker
table inet docker-filter {
# Set de IPs confiáveis que podem acessar containers
set trusted_ips {
type ipv4_addr
flags interval
elements = {
10.0.0.0/8,
172.16.0.0/12,
192.168.0.0/16
}
}
# Chain com prioridade menor que a do Docker (-1)
# para processar pacotes ANTES das regras do Docker
chain docker-user {
type filter hook forward priority -1; policy accept;
# Permitir tráfego entre containers (redes internas do Docker)
iifname "docker0" oifname "docker0" accept \
comment "Trafego inter-container"
# Permitir tráfego de retorno (conexões estabelecidas)
ct state { established, related } accept
# Permitir acesso apenas de IPs confiáveis
iifname != "docker0" oifname "docker0" \
ip saddr != @trusted_ips drop \
comment "Bloquear acesso externo nao autorizado"
}
}
Melhores Práticas: Reverse Proxy
Sinceramente, a abordagem mais segura pra containers Docker é nunca publicar portas diretamente. Use um reverse proxy (Nginx ou Traefik, por exemplo) que roda no host ou numa rede Docker dedicada:
- Containers escutam apenas em redes Docker internas (sem
-p) - O reverse proxy é o único serviço com portas publicadas (80 e 443)
- O firewall do host protege apenas as portas do reverse proxy
- TLS termination acontece no reverse proxy
# Exemplo: docker-compose.yml com reverse proxy
# O container da aplicação NÃO publica portas
# services:
# app:
# image: minha-app:latest
# networks:
# - internal
# # Sem "ports:" - sem exposição direta
#
# nginx:
# image: nginx:latest
# ports:
# - "80:80"
# - "443:443"
# networks:
# - internal
#
# networks:
# internal:
# driver: bridge
Logging e Monitoramento
Um firewall sem monitoramento é um firewall cego. E firewall cego não serve pra muita coisa. O nftables oferece várias ferramentas de logging e observabilidade que são essenciais pra detectar tentativas de intrusão e depurar regras.
Log com Prefixo
O nftables permite adicionar a ação log a qualquer regra, com um prefixo customizável pra facilitar a filtragem nos logs:
# Exemplos de regras com logging
tcp dport 22 ct state new log prefix "[nft-ssh-new] " accept
tcp dport 3306 log prefix "[nft-mysql-blocked] " drop
# Log com nível de severidade específico
tcp dport 23 log prefix "[nft-telnet] " level warn drop
Contadores Nomeados e Anônimos
Os contadores permitem rastrear quantos pacotes e bytes correspondem a cada regra. Existem dois tipos — nomeados e anônimos (inline):
table inet filter {
# Contadores nomeados — definidos uma vez, referenciados em regras
counter cnt_ssh_aceitos {
comment "Total de conexões SSH aceitas"
}
counter cnt_pacotes_descartados {
comment "Total de pacotes descartados pelo firewall"
}
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state invalid drop
ct state { established, related } accept
# Usando contadores nomeados
tcp dport 22 ct state new counter name cnt_ssh_aceitos accept
# Contador anônimo (inline)
tcp dport { 80, 443 } counter accept
# Contar pacotes descartados
counter name cnt_pacotes_descartados
}
}
# Visualizar os contadores
sudo nft list counters
# Saída de exemplo:
# table inet filter {
# counter cnt_ssh_aceitos {
# packets 1247 bytes 89784
# }
# counter cnt_pacotes_descartados {
# packets 53891 bytes 3234660
# }
# }
# Zerar todos os contadores
sudo nft reset counters
Logging com Rate Limiting usando Sets Dinâmicos
Sem rate limiting, um ataque DDoS pode gerar milhões de linhas de log e comer todo o espaço em disco do servidor. Não é exagero — já vi isso acontecer. Use rate limiting no próprio log:
# Log limitado a 5 mensagens por minuto com burst de 10
limit rate 5/minute burst 10 packets \
log prefix "[nft-drop-input] " drop
# Logging por IP com set dinâmico (evita flood de logs)
tcp dport 22 ct state new \
meter log_meter { ip saddr limit rate 1/minute } \
log prefix "[nft-ssh-attempt] "
nft monitor trace
O nft monitor trace é, na minha opinião, a ferramenta de depuração mais poderosa do nftables. Ele mostra em tempo real o caminho que cada pacote faz pelas chains e regras:
# Primeiro, adicione a ação meta nftrace set 1 em uma regra
# para habilitar o tracing para tráfego específico
sudo nft insert rule inet filter input \
tcp dport 22 meta nftrace set 1
# Iniciar o monitoramento em tempo real
sudo nft monitor trace
# Saída de exemplo:
# trace id 3a1b2c3d inet filter input
# packet: iif "eth0" ip saddr 203.0.113.50 ip daddr 198.51.100.10
# tcp sport 54321 tcp dport 22
# trace id 3a1b2c3d inet filter input rule
# tcp dport 22 ct state new limit rate 4/minute accept (verdict accept)
# Para encerrar, pressione Ctrl+C
# Não esqueça de remover a regra de trace após a depuração!
Separação de Logs com Rsyslog
Pra manter os logs do firewall separados e organizados (o que facilita muito na hora de investigar incidentes), configure o rsyslog pra redirecionar mensagens do nftables pra um arquivo dedicado:
# /etc/rsyslog.d/10-nftables.conf
# Redirecionar logs do nftables para arquivo dedicado
:msg, startswith, "[nft-" /var/log/nftables.log
& stop
# Alternativa usando regex para capturar diferentes prefixos
:msg, regex, "\\[nft[a-z-]*\\]" /var/log/nftables.log
& stop
# Reiniciar o rsyslog
sudo systemctl restart rsyslog
# Configurar rotação de logs
# /etc/logrotate.d/nftables
# /var/log/nftables.log {
# daily
# rotate 30
# compress
# delaycompress
# missingok
# notifempty
# postrotate
# /usr/lib/rsyslog/rsyslog-rotate
# endscript
# }
Boas Práticas e Checklist de Segurança
Configurou o firewall? Ótimo. Mas antes de considerar o trabalho feito, passe por essas boas práticas pra garantir que o hardening esteja realmente completo:
- Sempre use a política default deny — comece bloqueando tudo e abra apenas o necessário. Nunca, em hipótese alguma, use
policy acceptna chain input. - Utilize a família inet — proteja IPv4 e IPv6 ao mesmo tempo. Deixar o IPv6 desprotegido é um erro mais comum do que deveria ser.
- Salve e versionize o ruleset — mantenha
/etc/nftables.confnum repositório Git. Usenft list ruleset > backup_$(date +%Y%m%d).nftantes de qualquer alteração. - Teste antes de aplicar — use
nft -c -f /etc/nftables.confpra validar a sintaxe sem aplicar as regras. Isso pode te poupar uma viagem ao datacenter. - Implemente rate limiting per-IP para SSH — meters dinâmicos são muito mais eficazes que limitação global.
- Bloqueie pacotes inválidos — descarte pacotes com
ct state invalidantes de qualquer outra regra. - Limite o ICMP — permita apenas os tipos necessários e aplique rate limiting.
- Habilite logging para regras de drop — mas com rate limiting, senão o disco enche rápido.
- Use contadores nomeados — pra monitorar tráfego em regras críticas e detectar anomalias.
- Separe regras por responsabilidade — use arquivos incluídos via
includepra Fail2Ban, Docker, geo-blocking. - Não exponha portas de banco de dados — MySQL (3306), PostgreSQL (5432), Redis (6379) e MongoDB (27017) devem ser acessíveis apenas via loopback ou VPN. Sempre.
- Atualize o kernel regularmente — o kernel 6.19.5 trouxe otimizações importantes pra sets com o backend pipapo.
- Documente cada regra — use o campo
commentem todas as regras. Seu eu do futuro agradece.
Checklist Resumido
| Item | Status | Comando de Verificação |
|---|---|---|
| nftables instalado e habilitado | Obrigatório | systemctl is-enabled nftables |
| Política default deny na chain input | Obrigatório | nft list chain inet filter input |
| Pacotes inválidos descartados | Obrigatório | nft list ruleset | grep invalid |
| Conexões estabelecidas permitidas | Obrigatório | nft list ruleset | grep established |
| SSH com rate limiting per-IP | Obrigatório | nft list meters |
| ICMPv4 e ICMPv6 com rate limiting | Recomendado | nft list ruleset | grep icmp |
| Logging de pacotes descartados | Recomendado | nft list ruleset | grep log |
| Contadores nomeados em regras críticas | Recomendado | nft list counters |
| Fail2Ban integrado com nftables | Recomendado | fail2ban-client status |
| Backup do ruleset em Git | Recomendado | git log /etc/nftables.conf |
| Logs separados via rsyslog | Opcional | ls -la /var/log/nftables.log |
| Docker usando backend nftables | Opcional | docker info | grep nftables |
Perguntas Frequentes (FAQ)
Qual a diferença entre nftables e iptables?
Em resumo, o nftables é o sucessor do iptables e o framework padrão de firewall no kernel Linux desde a versão 3.13 (2014). As diferenças principais: o nftables usa um único comando (nft) em vez de quatro comandos separados; suporta a família inet pra processar IPv4 e IPv6 com um único conjunto de regras; usa sets nativos com desempenho O(1); faz atualizações atômicas do ruleset; e não vem com chains predefinidas, te dando mais controle. O iptables tá oficialmente deprecated e é mantido apenas pela camada de compatibilidade iptables-nft.
Como migrar regras do iptables para nftables?
A migração pode ser feita aos poucos usando a ferramenta iptables-translate, que converte regras individuais do iptables pra sintaxe do nftables. Pra converter um ruleset completo, use iptables-save | iptables-restore-translate:
# Traduzir uma regra individual
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# Saída: nft add rule ip filter INPUT tcp dport 22 counter accept
# Traduzir o ruleset completo
iptables-save | iptables-restore-translate -f /etc/nftables.conf
# Verificar a tradução antes de aplicar
nft -c -f /etc/nftables.conf
Depois da tradução, revise manualmente o resultado pra aproveitar recursos exclusivos do nftables como a família inet, sets e meters dinâmicos — coisas que não têm equivalente direto no iptables.
O nftables funciona com Docker?
Sim, mas com ressalvas. Historicamente, o Docker usava exclusivamente o iptables pro NAT e encaminhamento de pacotes, criando conflitos com regras de firewall manuais. A partir do Docker 29.0.0, existe suporte experimental ao backend nftables — basta configurar em /etc/docker/daemon.json com "features": {"nftables": true}. Pra versões anteriores, a melhor prática é criar uma chain de forward com prioridade -1 que filtre tráfego antes das chains do Docker, ou usar a abordagem de reverse proxy pra evitar publicar portas diretamente.
Como verificar se o nftables está ativo no meu sistema?
Tem alguns comandos úteis pra isso:
# Verificar se o serviço está ativo
sudo systemctl status nftables
# Verificar a versão instalada
nft --version
# Listar todas as regras ativas
sudo nft list ruleset
# Verificar se o módulo do kernel está carregado
lsmod | grep nf_tables
# Verificar se o iptables está usando o backend nftables
iptables -V
# Se mostrar "(nf_tables)", o iptables está usando nftables por baixo
Se o nft list ruleset voltar vazio, o nftables tá instalado mas sem regras carregadas. Nesse caso, aplique seu arquivo de configuração com nft -f /etc/nftables.conf e habilite o serviço com systemctl enable nftables pra que as regras persistam entre reinicializações.
O nftables substitui completamente o firewalld?
Não exatamente — eles operam em camadas diferentes. O nftables é o framework no nível do kernel, responsável pelo processamento real dos pacotes. O firewalld é uma ferramenta de gerenciamento de alto nível que oferece uma interface mais amigável (com zonas e serviços) e gera regras internamente. Desde a versão 0.6.0, o firewalld usa o nftables como backend padrão.
Você pode usar o firewalld se preferir a abstração de zonas, ou configurar o nftables diretamente pra ter controle total sobre cada regra. Em ambientes de produção com hardening rigoroso, eu pessoalmente prefiro o nftables direto — a transparência de saber exatamente o que está sendo aplicado compensa o trabalho extra de configuração.