iptables считается deprecated примерно с 2014 года, но в проде у большинства людей он всё ещё стоит. Я тоже долго откладывал миграцию, потому что «работает — не трогай». Но в Debian 12 и Ubuntu 24.04 nftables уже стоит по дефолту, а iptables — это просто враппер поверх nft. Так что рано или поздно мигрировать всё равно придётся. Расскажу, как я это сделал на нескольких боевых нодах без даунтайма.
Что меняется
iptables — это набор инструментов, которые управляют netfilter через старые API (iptables, ip6tables, arptables, ebtables — четыре разных бинаря). nftables — это единый бинарь nft, который покрывает все четыре, плюс более быстрый matching, более гибкие правила и нормальные структуры данных (sets, maps, dictionaries).
С точки зрения ядра: оба используют netfilter, но nftables — более новый API, с компилируемыми VM-инструкциями вместо последовательного перебора правил. Это значит, что nftables-фильтр на 1000 правил работает заметно быстрее, чем iptables на 1000 правил.
Простой перевод существующих правил
Если у вас уже есть iptables-конфиг, его можно перевести автоматом:
iptables-save > /tmp/old-rules.v4
iptables-restore-translate -f /tmp/old-rules.v4 > /tmp/new-rules.nft
Получится примерно такое:
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy drop; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy drop; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip filter INPUT iifname "lo" counter accept
add rule ip filter INPUT ct state related,established counter accept
add rule ip filter INPUT tcp dport 22 counter accept
Это валидный nftables-конфиг, можно применять через nft -f /tmp/new-rules.nft. Но обычно после автоконверта я переписываю руками — получается чище и идиоматичнее.
Тот же конфиг по-человечески
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
ct state invalid drop
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
tcp dport { 22, 80, 443 } accept
# rate-limit SSH brute
tcp dport 22 ct state new limit rate 5/minute accept
# лог дропов с rate-limit, чтоб не флудить
limit rate 10/minute log prefix "[nft drop] " level info
counter
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
Обратите внимание на table inet filter — это объединённая таблица для IPv4 и IPv6. В iptables нужно было дублировать всё в iptables и ip6tables. В nftables — одна таблица обрабатывает оба протокола.
tcp dport { 22, 80, 443 } — это anonymous set. В iptables то же самое — три отдельных правила. В nftables — одно правило с set-lookup, и оно работает быстрее.
Что реально круто в nftables: sets и maps
Допустим, у вас есть динамический whitelist IP, который надо обновлять без перезагрузки правил. В iptables — ipset (отдельная утилита). В nftables — это нативно:
table inet filter {
set admin_ips {
type ipv4_addr
flags interval
elements = {
10.0.0.0/8,
192.168.1.5,
203.0.113.0/24
}
}
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
ip saddr @admin_ips tcp dport 22 accept
}
}
Добавить IP в set на лету:
nft add element inet filter admin_ips { 1.2.3.4 }
nft delete element inet filter admin_ips { 1.2.3.4 }
nft list set inet filter admin_ips
Это полная замена ipset, без танцев с отдельной утилитой.
Maps — то же самое, но key-value. Пример — port forwarding по dest-IP:
table ip nat {
map portmap {
type ipv4_addr : inet_service
elements = {
192.0.2.10 : 8080,
192.0.2.11 : 9090
}
}
chain prerouting {
type nat hook prerouting priority -100;
tcp dport 443 dnat to ip daddr map @portmap
}
}
Миграция на боевой ноде
Главное правило — не выключать iptables, пока не убедились, что nftables работает. К счастью, они могут сосуществовать (с оговорками — оба не должны иметь правил в одних и тех же хуках, иначе порядок поведения непредсказуем).
План:
- Сохраняем старые iptables-правила:
iptables-save > /root/iptables.backup - Пишем nftables-конфиг в
/etc/nftables.conf, но не применяем - Применяем через
nft -f /etc/nftables.conf— через KVM-консоль или out-of-band, не через SSH. Если ошибёмся — потеряем доступ - Проверяем, что сервисы доступны
- Чистим iptables:
iptables -F,iptables -X, и так для всех таблиц systemctl disable iptables(если был включён) иsystemctl enable nftables
Команда для подключения через KVM-консоль — критически важна. У меня был один раз случай: применил правила через SSH без двойной проверки, забыл строчку про ssh accept, потерял доступ к ноде на час, пока админ хостинга поднимал из rescue.
Persist между ребутами
Debian/Ubuntu — пакет nftables, который ставит systemd-юнит:
apt install nftables
systemctl enable --now nftables
Юнит загружает /etc/nftables.conf при старте. Главное — выставить там shebang и сделать файл исполняемым:
chmod +x /etc/nftables.conf
Альтернатива — nft list ruleset > /etc/nftables.conf после ручной настройки.
Грабли, которые встретил
Двойная фильтрация
Когда iptables-legacy и nftables оба активны, можно нечаянно создать ситуацию, что правило accept в одной таблице конфликтует с drop в другой. Симптом — соединения «то работают, то нет». Проверка:
update-alternatives --display iptables
# должно показать iptables-nft, а не iptables-legacy
Если стоит legacy — переключите:
update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
docker и k8s
Docker сам управляет своими правилами в iptables. На свежих версиях docker (27+) он умеет писать в nft-таблицы корректно, но мониторинг типа fail2ban (если использует action iptables-multiport) может ломаться. Лучше переводить fail2ban на action nftables-multiport.
Старые скрипты
Если у вас есть какие-то wrapper-скрипты, которые iptables -I INPUT 1 -j ACCEPT ... — они продолжат работать через iptables-nft, но добавятся в отдельную таблицу ip filter, не в вашу основную inet filter. Лучше переписать.
Итог
Миграция на nftables — не страшно, но требует осторожности с боевыми правилами. Главное — конвертируйте, применяйте через KVM, не через SSH, и не забудьте переключить update-alternatives. После переезда вы получаете единые правила для IPv4/IPv6, нативные sets и maps без ipset, и более быстрый matching на больших конфигурациях. Возвращаться на legacy iptables после этого нет ни одной причины.