nftables — современный фреймворк фильтрации пакетов Linux, заменяющий iptables, ip6tables, arptables и ebtables. Управление выполняется утилитой nft; правила объединяются в таблицы и цепочки.
1. Базовая модель nftables
Иерархия правил: family → table → chain → rule
- Family — семейство протоколов:
ip(IPv4),ip6(IPv6),inet(IPv4 + IPv6),arp,bridge,netdev. - Table — логический контейнер цепочек и объектов.
- Chain — последовательность правил. Бывает базовой (base chain, подключена к сетевому стеку через hook) или обычной (regular chain, вызывается через jump/goto).
- Rule — условие и действие:
tcp dport 22 accept,ip saddr 10.0.0.0/8 dropи т. п.
Для универсального firewall обычно используется family inet: одна таблица одновременно обслуживает IPv4 и IPv6.
2. Установка, служба и диагностика
# Debian/Ubuntu
sudo apt update
sudo apt install nftables
# Запустить и включить при старте
sudo systemctl enable --now nftables
# Проверить состояние службы
sudo systemctl status nftables
# Вывести весь активный ruleset
sudo nft list ruleset
# Вывести ruleset вместе с handle каждого правила
sudo nft -a list ruleset
# Проверить синтаксис файла без применения
sudo nft -c -f /etc/nftables.conf
В дистрибутивах с systemd обычно постоянная конфигурация хранится в /etc/nftables.conf, а сервис nftables загружает её при запуске.
3. Важные правила безопасного применения
Перед удалённой настройкой firewall:
- Откройте второе SSH-подключение или консоль через IPMI/iDRAC/Proxmox.
- Сначала добавьте правило, разрешающее текущий SSH-доступ.
- Проверяйте конфигурацию:
sudo nft -c -f /etc/nftables.conf. - Применяйте файл:
sudo nft -f /etc/nftables.conf. - Сразу проверьте:
sudo nft -a list ruleset.
4. Таблицы: создание, просмотр, очистка, удаление
Создать таблицу
# Общая таблица для IPv4 и IPv6
sudo nft add table inet filter
# Только IPv4
sudo nft add table ip filter4
# Только IPv6
sudo nft add table ip6 filter6
Просмотреть таблицы
# Список таблиц
sudo nft list tables
# Содержимое конкретной таблицы
sudo nft list table inet filter
Очистить или удалить таблицу
# Удалить правила и цепочки из таблицы, но оставить таблицу
sudo nft flush table inet filter
# Полностью удалить таблицу
sudo nft delete table inet filter
flush table удаляет содержимое таблицы. delete table удаляет и саму таблицу.
5. Цепочки: base chain и regular chain
Base chain
Базовая цепочка подключается к одной из точек обработки пакета (hook) и получает пакеты от сетевого стека.
Основные hook для firewall:
| Hook | Направление | Назначение |
|---|---|---|
| input | Входящие на локальный хост | SSH, веб-сервер, DNS на самом сервере |
| forward | Транзит через хост / роутер | VPN-шлюз, Docker-хост, межсетевой экран |
| output | Исходящие с локального хоста | Ограничение исходящих соединений |
| prerouting | До выбора маршрута | NAT/DNAT, ранняя фильтрация |
| postrouting | После выбора маршрута | NAT/SNAT/masquerade |
Создать базовые цепочки фильтрации
# Input: пакеты, адресованные самому хосту
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
# Forward: транзитные пакеты
sudo nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'
# Output: пакеты, созданные локально
sudo nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'
policy drop действует только если ни одно правило в базовой цепочке не выдало окончательный verdict (accept, drop, reject).
Создать обычную цепочку
Обычная цепочка не имеет type, hook и priority. Она вызывается из другой цепочки.
# Цепочка для SSH
sudo nft add chain inet filter ssh_in
# Цепочка для сервисов веб-сервера
sudo nft add chain inet filter web_in
Разница между jump и goto
# jump: выполнить ssh_in и вернуться к следующему правилу текущей цепочки
sudo nft add rule inet filter input tcp dport 22 jump ssh_in
# goto: перейти в ssh_in и не возвращаться в текущую цепочку
sudo nft add rule inet filter input tcp dport 22 goto ssh_in
Практически для модульных firewall-конфигураций чаще используют jump.
Просмотр, очистка и удаление цепочек
# Вывести одну цепочку
sudo nft list chain inet filter input
# Вывести правила и handles
sudo nft -a list chain inet filter input
# Удалить все правила из цепочки, оставив цепочку
sudo nft flush chain inet filter ssh_in
# Удалить пустую regular chain
sudo nft delete chain inet filter ssh_in
# Удалить base chain: сначала очистить её и удалить обращения jump/goto
sudo nft flush chain inet filter input
sudo nft delete chain inet filter input
Цепочку нельзя удалить, пока в ней есть правила или на неё ссылаются правила jump/goto. Для удаления сначала удалите ссылки, затем очистите цепочку.
6. Правила: добавление, вставка, замена, удаление
Добавить правило в конец цепочки
# Разрешить SSH
sudo nft add rule inet filter input tcp dport 22 accept
# Разрешить HTTP/HTTPS
sudo nft add rule inet filter input tcp dport { 80, 443 } accept
# Разрешить ICMP и ICMPv6
sudo nft add rule inet filter input ip protocol icmp accept
sudo nft add rule inet filter input meta l4proto ipv6-icmp accept
Вставить правило в начало цепочки
Это важно для SSH-исключения, если ниже уже есть drop.
# Вставить правило первым
sudo nft insert rule inet filter input tcp dport 22 accept
Вставить правило перед/после конкретного handle
# Показать handles
sudo nft -a list chain inet filter input
# Вставить правило перед правилом с handle 12
sudo nft insert rule inet filter input position 12 tcp dport 443 accept
# Добавить правило после handle 12
sudo nft add rule inet filter input position 12 tcp dport 443 accept
Заменить правило
# Сначала посмотреть handle
sudo nft -a list chain inet filter input
# Заменить правило с handle 7
sudo nft replace rule inet filter input handle 7 tcp dport 22 ct state new limit rate 10/minute accept
Удалить правило по handle
# Найти handle
sudo nft -a list chain inet filter input
# Пример вывода:
# tcp dport 22 accept comment "SSH" # handle 5
# Удалить правило
sudo nft delete rule inet filter input handle 5
handle — идентификатор конкретного правила в текущем активном ruleset. После перезагрузки/пересоздания ruleset номера handle могут измениться, поэтому всегда получайте их заново перед удалением.
7. Основные выражения и verdict
Состояние соединения conntrack
# Пропускать established и related трафик
sudo nft add rule inet filter input ct state established,related accept
# Разрешать только новые SSH-соединения
sudo nft add rule inet filter input tcp dport 22 ct state new accept
# Отбрасывать invalid-пакеты
sudo nft add rule inet filter input ct state invalid drop
Адреса и подсети
# Разрешить SSH только с одного IPv4-адреса
sudo nft add rule inet filter input ip saddr 192.168.1.10 tcp dport 22 accept
# Разрешить PostgreSQL только из внутренней подсети
sudo nft add rule inet filter input ip saddr 10.10.10.0/24 tcp dport 5432 accept
# Разрешить IPv6-подсеть
sudo nft add rule inet filter input ip6 saddr 2001:db8:10::/64 tcp dport 22 accept
# Заблокировать IP
sudo nft add rule inet filter input ip saddr 203.0.113.25 drop
Интерфейсы
# Разрешить loopback
sudo nft add rule inet filter input iifname "lo" accept
# Разрешить SSH только через eth0
sudo nft add rule inet filter input iifname "eth0" tcp dport 22 accept
# Forward из LAN в WAN
sudo nft add rule inet filter forward iifname "lan0" oifname "wan0" accept
Порты и протоколы
# Один TCP-порт
sudo nft add rule inet filter input tcp dport 22 accept
# Несколько TCP-портов
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept
# Диапазон TCP-портов
sudo nft add rule inet filter input tcp dport 6000-6010 accept
# DNS UDP и TCP
sudo nft add rule inet filter input udp dport 53 accept
sudo nft add rule inet filter input tcp dport 53 accept
Действия (verdict)
# Разрешить
accept
# Молча отбросить
drop
# Отклонить с ICMP/ICMPv6 ответом
reject
# Перейти в regular chain
jump ssh_in
# Перейти без возврата
goto ssh_in
# Вернуться из regular chain
return
8. Логирование, счётчики и rate limit
# Логировать и отбросить трафик
sudo nft add rule inet filter input log prefix "nft-input-drop: " flags all counter drop
# Добавить счётчик к разрешающему правилу
sudo nft add rule inet filter input tcp dport 443 counter accept
# Ограничить новые SSH-соединения: 10 в минуту, bursts до 15
sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 10/minute burst 15 packets accept
# Логировать не чаще 5 сообщений в секунду
sudo nft add rule inet filter input limit rate 5/second log prefix "nft-drop: " counter drop
# Посмотреть срабатывания counter
sudo nft list chain inet filter input
Логи обычно попадают в kernel journal:
sudo journalctl -k -f
# или
sudo dmesg -w
9. Sets: списки адресов и портов
Sets делают конфигурацию компактной и удобной для сопровождения.
# Создать IPv4 set
sudo nft add set inet filter trusted_v4 '{ type ipv4_addr; flags interval; }'
# Добавить адреса и подсети
sudo nft add element inet filter trusted_v4 '{ 10.0.0.0/8, 192.168.10.0/24, 203.0.113.10 }'
# Разрешить SSH только доверенным адресам
sudo nft add rule inet filter input ip saddr @trusted_v4 tcp dport 22 accept
# Посмотреть set
sudo nft list set inet filter trusted_v4
# Удалить элемент
sudo nft delete element inet filter trusted_v4 '{ 203.0.113.10 }'
# Удалить set: сначала убрать все ссылки на него из правил
sudo nft delete set inet filter trusted_v4
Set портов
# Создать set TCP-портов
sudo nft add set inet filter allowed_tcp_ports '{ type inet_service; }'
# Заполнить портами
sudo nft add element inet filter allowed_tcp_ports '{ 22, 80, 443 }'
# Использовать в правиле
sudo nft add rule inet filter input tcp dport @allowed_tcp_ports accept
10. NAT: DNAT, SNAT и masquerade
Таблица и base chain для NAT
sudo nft add table ip nat
sudo nft add chain ip nat prerouting '{ type nat hook prerouting priority dstnat; policy accept; }'
sudo nft add chain ip nat postrouting '{ type nat hook postrouting priority srcnat; policy accept; }'
Примеры NAT
# DNAT: проброс WAN:443 на внутренний сервер 10.10.10.20:8443
sudo nft add rule ip nat prerouting iifname "wan0" tcp dport 443 dnat to 10.10.10.20:8443
# SNAT: статический публичный адрес
sudo nft add rule ip nat postrouting oifname "wan0" ip saddr 10.10.10.0/24 snat to 198.51.100.10
# Masquerade: адрес на WAN динамический
sudo nft add rule ip nat postrouting oifname "wan0" ip saddr 10.10.10.0/24 masquerade
Для маршрутизации также включите IPv4 forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
# Постоянно: создать файл /etc/sysctl.d/99-forwarding.conf
printf 'net.ipv4.ip_forward=1\n' | sudo tee /etc/sysctl.d/99-forwarding.conf
sudo sysctl --system
11. Постоянная конфигурация: /etc/nftables.conf
Ниже — минимальный рабочий конфиг сервера. Перед применением замените интерфейс/порты и убедитесь, что SSH-порт указан корректно.
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state established,related accept
ct state invalid drop
# IPv4/IPv6 ICMP: ping, path MTU discovery и служебные сообщения
ip protocol icmp accept
meta l4proto ipv6-icmp accept
# Управление и веб-сервисы
tcp dport 22 ct state new accept
tcp dport { 80, 443 } ct state new accept
# Финальное логирование и блокировка
limit rate 5/second log prefix "nft-input-drop: " flags all counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Применение:
# Проверить синтаксис
sudo nft -c -f /etc/nftables.conf
# Загрузить конфигурацию
sudo nft -f /etc/nftables.conf
# Посмотреть активные правила и handles
sudo nft -a list ruleset
# Обеспечить загрузку после перезагрузки
sudo systemctl enable nftables
flush ruleset в начале файла полностью очищает текущие правила перед загрузкой файла. Не смешивайте этот конфиг с правилами, которыми управляют UFW, Docker, Kubernetes или другой firewall-менеджер, без предварительной проверки интеграции.
12. Типовые сценарии
Веб-сервер
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state established,related accept
ct state invalid drop
ip protocol icmp accept
meta l4proto ipv6-icmp accept
tcp dport 22 ct state new accept
tcp dport { 80, 443 } ct state new accept
counter drop
}
Сервер PostgreSQL из внутренней сети
chain input {
type filter hook input priority filter; policy drop;
iifname "lo" accept
ct state established,related accept
ip saddr 10.10.10.0/24 tcp dport 5432 ct state new accept
ip saddr 10.10.10.0/24 tcp dport 22 ct state new accept
counter drop
}
Роутер: LAN → WAN с NAT
table inet filter {
chain forward {
type filter hook forward priority filter; policy drop;
ct state established,related accept
iifname "lan0" oifname "wan0" accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "wan0" ip saddr 10.10.10.0/24 masquerade
}
}
13. Удаление объектов: порядок действий
Если нужно удалить модульную конфигурацию, соблюдайте зависимости:
# 1. Посмотреть активную конфигурацию с handles
sudo nft -a list ruleset
# 2. Удалить правила, которые ссылаются на regular chain/set
sudo nft delete rule inet filter input handle 15
# 3. Очистить и удалить regular chain
sudo nft flush chain inet filter ssh_in
sudo nft delete chain inet filter ssh_in
# 4. Удалить set (если он больше нигде не используется)
sudo nft delete set inet filter trusted_v4
# 5. Очистить и удалить таблицу
sudo nft flush table inet filter
sudo nft delete table inet filter
14. Полезные команды диагностики
# Полный ruleset
sudo nft list ruleset
# С handles
sudo nft -a list ruleset
# В машинно-обрабатываемом JSON
sudo nft -j list ruleset
# Мониторинг изменений ruleset в реальном времени
sudo nft monitor ruleset
# Мониторинг трассировки пакетов (использовать осторожно)
sudo nft monitor trace
# Проверить загрузку systemd-конфига
sudo systemctl status nftables
sudo journalctl -u nftables -b
15. Быстрая шпаргалка
# Таблица
nft add table inet filter
# Base chain
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
# Regular chain
nft add chain inet filter ssh_in
# Правило
nft add rule inet filter input tcp dport 22 accept
# Посмотреть handles
nft -a list chain inet filter input
# Удалить правило по handle
nft delete rule inet filter input handle 5
# Очистить chain
nft flush chain inet filter input
# Удалить пустую chain
nft delete chain inet filter input
# Удалить таблицу
nft delete table inet filter
16. Частые ошибки
| Симптом | Возможная причина | Проверка / решение |
|---|---|---|
| Потерян SSH после применения | Нет разрешающего правила до policy drop | Через консоль добавить nft insert rule inet filter input tcp dport 22 accept |
| No such file or directory | Нет таблицы или цепочки | Проверить nft list tables, затем создать нужный объект |
| Device or resource busy при удалении | Есть правила или ссылки jump/goto | Удалить ссылки, выполнить flush chain, затем delete chain |
| Не работает DNAT | Нет разрешения в forward или выключен IP forwarding | Добавить правило в forward, включить net.ipv4.ip_forward=1 |
| Правила исчезли после reboot | Конфигурация не сохранена / служба выключена | Записать /etc/nftables.conf, выполнить systemctl enable --now nftables |
| Docker/Kubernetes ведут себя непредсказуемо | Несогласованное управление правилами | Не выполнять бездумный flush ruleset; проектировать интеграцию отдельно |