Перейти к содержимому

nftables: современный firewall для Linux-сервера

Предупреждение

Перед работой с nftables убедитесь, что есть физический или console-доступ к серверу. Ошибочная цепочка input может заблокировать SSH и отсечь от машины.

nftables пришёл на смену iptables в ядре Linux начиная с версии 3.13. Если вы всё ещё пишете правила в стиле iptables — пора пересмотреть подход. nftables быстрее, имеет встроенную поддержку IPv4/IPv6 в одном интерфейсе и позволяет работать с ruleset как с целым, а не набирать команды по одной.

Зачем переходить с iptables

iptables имеет несколько фундаментальных проблем. Каждая таблица (filter, nat, mangle) — отдельный набор правил с собственной семантикой. Нет встроенной поддержки одновременной работы с IPv4 и IPv6 — приходится писать два набора правил. Производительность падает при большом количестве правил из-за линейного поиска.

nftables решает это иначе. Все протоколы работают в единой структуре данных — ruleset. Ядро компилирует правила в эффективные структуры поиска. Атомарная замена ruleset исключает race condition при обновлении правил.

Предупреждение

В дистрибутивах на базе RHEL 8 и новее iptables по умолчанию перенаправляется в nftables. В Ubuntu 22.04 и старше — аналогично. Проверьте update-alternatives --display iptables.

Базовые команды: просмотр и сброс правил

Первая команда, которую стоит запомнить:

nft list ruleset

Вывод показывает все таблицы, цепочки и правила. Без таблиц вывод пуст — это нормально.

Создаём таблицу с именем filter для работы с пакетами:

nft add table inet filter

inet означает, что таблица обрабатывает оба протокола. Для IPv4-only — ip, для IPv6 — ip6.

Добавляем цепочку для входящего трафика:

nft add chain inet filter input { type filter hook input priority 0 \; policy accept \; }

Разберём флаги:

ФлагНазначение
type filterТип цепочки — фильтрация пакетов
hook inputТочка подключения — входящие пакеты
priority 0Порядок обработки относительно других хуков
policy acceptДефолтное действие — пропускать всё

Сброс правил в цепочке:

nft flush chain inet filter input

Удаление всей таблицы:

nft delete table inet filter

Добавление и удаление правил по handle

Создадим несколько правил и посмотрим их handle:

nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp dport 80 accept
nft add rule inet filter input tcp dport 443 accept
nft list ruleset

Вывод покажет что-то вроде:

table inet filter {
    chain input {
        type filter hook input priority 0; policy accept;
        tcp dport 22 accept
        tcp dport 80 accept
        tcp dport 443 accept
    }
}

Handle скрыт в выводе по умолчанию. Для работы с конкретным правилом:

nft -a list ruleset

Добавим -a и увидим handle для каждого правила. Теперь можем удалять по номеру:

nft delete rule inet filter input handle 3
Подсказка

Handle меняется при каждом добавлении или удалении правила. Если скрипт модифицирует ruleset, сохраняйте вывод nft -a list ruleset в файл для отслеживания.

Добавим правило с приоритетом перед существующими — в начало цепочки:

nft insert rule inet filter input tcp dport 2222 accept

Команда add добавляет в конец, insert — в начало. Для вставки в конкретную позицию:

nft add rule inet filter input position 2 tcp dport 8080 accept

Атомарная замена ruleset

Ручное добавление правил по одному создаёт промежуток времени, когда часть правил уже активна, а часть — ещё нет. Для продакшена это неприемлемо.

Решение — записать полный ruleset в файл и загрузить атомарно:

nft list ruleset > /etc/nftables.conf

Файл /etc/nftables.conf — стандартное место в большинстве дистрибутивов. Теперь редактируем его:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        
        ct state established,related accept
        ct state invalid drop
        
        iif lo accept
        
        tcp dport 22 accept
        tcp dport 80 accept
        tcp dport 443 accept
        
        counter drop
    }
}

Загружаем:

nft -f /etc/nftables.conf
Примечание

flush ruleset перед загрузкой очищает всё. Если нужно добавить правила к существующим — уберите эту строку.

Проверяем без применения:

nft -c -f /etc/nftables.conf

Флаг -c выполняет синтаксическую проверку без изменения состояния. Полезно в CI/CD перед деплоем.

Чтобы правила переживали перезагрузку в systemd-дистрибутивах:

systemctl enable --now nftables

nftables.service загружает /etc/nftables.conf при старте. После правки файла применяйте systemctl restart nftables.

Цепочка forward

Если машина не роутер, forward оставляют пустым с политикой drop. Когда включён IP-forwarding, минимум — ответы на установленные соединения и транзит между интерфейсами:

nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add rule inet filter forward ct state established,related accept
nft add rule inet filter forward iifname "eth0" oifname "eth1" accept

Для отладки можно логировать пакеты перед неявным drop:

nft add rule inet filter forward log prefix "nft-forward-drop: " level warn

Логи появятся в journalctl -k или /var/log/kern.log.

Типовые сценарии: блокировка порта и IP

Блокировка входящего подключения с конкретного IP:

nft add rule inet filter input ip saddr 1.2.3.4 drop

Блокировка исходящего на конкретный IP:

nft add rule inet filter output ip daddr 5.6.7.8 drop

Блокировка диапазона IP (CIDR):

nft add rule inet filter input ip saddr 10.0.0.0/8 drop

Блокировка порта для всех:

nft add rule inet filter input tcp dport 25 drop

Разрешить порт только для конкретной подсети:

nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 5432 accept

Логирование отброшенных пакетов:

nft add rule inet filter input counter drop

Счётчики видны в выводе nft list ruleset — показывают количество пакетов и байт.

NAT через маскарадинг

Для выхода локальной сети в интернет через один IP-адрес:

nft add table ip nat
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip nat postrouting ip saddr 192.168.0.0/24 masquerade

Маскарадинг автоматически подставляет внешний IP интерфейса. Для NAT с пробросом портов:

nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add rule ip nat prerouting tcp dport 8080 dnat to 192.168.0.100:80
Предупреждение

NAT в nftables работает только для IPv4. Для IPv6 используйте stateless NAT66 или адресацию на уровне маршрутизации.

Режим совместимости iptables-nft

В некоторых дистрибутивах iptables остаётся «работающей» за счёт трансляции в nftables:

update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft

Проблема в том, что это два разных мира правил. iptables-nft транслирует команды в nftables, но обратная совместимость не работает. Правила, созданные через iptables, не увидите в nft list ruleset напрямую.

Предупреждение

Не используйте одновременно iptables и nftables. Результат непредсказуем. Либо полностью переходите на nftables, либо остаётесь на iptables. Проверьте текущий режим: iptables -V покажет, используется iptables-legacy или iptables-nft.

Для миграции с iptables есть утилита iptables-translate:

iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT

Вывод: nft add rule ip filter input tcp dport 22 accept. Ручная проверка вывода обязательна — автоматическая трансляция не идеальна.

nftables — это не будущее, а настоящее. Если вы администрируете Linux-серверы, потратьте вечер на миграцию. Файл /etc/nftables.conf с полным ruleset — это ваш бэкап и деплой в одном флаконе.