# firewalld vs nftables - что выбрать _Безопасность · LinuxLab Knowledge Base_ **TL;DR:** firewalld - daemon-обёртка с zones, services, rich-rules; backend с RHEL 8 - nftables. Чистый nft - больше контроля, sets, atomic reload. firewalld для desktop/multi-zone, nft для server-fleet. ## Зачем выбирать В Linux в 2026 четыре актуальных способа управлять netfilter: | Тулинг | Уровень | Где default | |--------|---------|-------------| | **[cmd-iptables](/kb/cmd-iptables.md)** | низкий, legacy | Ubuntu LTS, embedded, Docker (всё ещё) | | **[cmd-nft](/kb/cmd-nft.md)** | низкий, modern | Debian 11+, Ubuntu 22+, прямой kernel-API | | **firewalld** | высокий | RHEL/CentOS/Fedora server | | **ufw** | высокий | Ubuntu desktop | iptables vs nftables, техническая дилемма (legacy vs modern, rules-replay vs atomic). firewalld vs чистый nft, **архитектурная дилемма**: оркестрируешь ты сам или daemon. ufw в этом сравнении упрощённый firewalld для Ubuntu. ## firewalld, что это Daemon, который читает XML-конфиги и применяет их к netfilter через бэкенд (с RHEL 8, `nftables`, до того, `iptables`): ``` /usr/share/firewalld/ ← дистрибуция-default /etc/firewalld/ ← кастомизация ├─ firewalld.conf ← глобальный конфиг ├─ zones/ ← XML, описывающие zones │ ├─ public.xml │ ├─ trusted.xml │ └─ work.xml ├─ services/ ← XML, описывающие services │ ├─ ssh.xml │ └─ http.xml └─ icmptypes/ ``` Команды через `firewall-cmd`: ```bash firewall-cmd --state # запущен ли firewall-cmd --get-active-zones firewall-cmd --get-default-zone firewall-cmd --list-all # текущая зона детально # Открыть HTTP постоянно firewall-cmd --permanent --add-service=http firewall-cmd --reload # Произвольный порт firewall-cmd --permanent --add-port=8080/tcp # Удалить firewall-cmd --permanent --remove-service=http ``` `--permanent` пишет в XML; без него, runtime-only (потеряется при reload). Часто делают: сначала без `--permanent` для теста, потом `--runtime-to-permanent` для commit. ## Zones, концепция firewalld Каждый сетевой интерфейс / source-IP принадлежит **зоне**. Зона это **уровень доверия** + список разрешённых services/ports. Дефолтные зоны: | Zone | По умолчанию | |------|--------------| | **drop** | всё drop, нет ответов | | **block** | всё reject (с ICMP unreachable) | | **public** | default; разрешён ssh, dhcpv6-client | | **external** | для NAT, MASQUERADE включён | | **dmz** | разрешён ssh; на внешний интерфейс к DMZ-машинам | | **work** | разрешено ssh, dhcpv6-client, mdns | | **home** | + samba, mdns; для дом-сети | | **internal** | как home | | **trusted** | всё разрешено | Привязка интерфейса: ```bash firewall-cmd --zone=trusted --change-interface=eth1 --permanent ``` Привязка source-IP: ```bash firewall-cmd --zone=trusted --add-source=10.0.0.0/24 --permanent ``` Источники приоритетнее интерфейсов. Если src попадает в зону X трафик идёт по правилам X, неважно какой интерфейс. Это сильная сторона firewalld: один и тот же сервер может говорить разные правила разным сетям без сложных rule-cascade. ## Rich rules, кастомизация в firewalld Когда services/ports мало, есть **rich-rules**, DSL для сложных правил: ```bash firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="10.0.0.0/24" service name="http" log prefix="http-from-internal: " level="info" accept' firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="1.2.3.4" drop' firewall-cmd --permanent --add-rich-rule=' rule service name="ssh" accept limit value="3/m"' # rate-limit ``` Удобно: ipset-style, rate-limit, log, accept/reject/drop. Под капотом всё-равно компилируется в nftables. ## Чистый nft, Pro Прямой контроль: ```nft # /etc/nftables.conf table inet filter { set blocked_ips { type ipv4_addr flags interval elements = { 1.2.3.0/24, 5.6.7.8 } } chain input { type filter hook input priority filter; policy drop; ct state established,related accept iif lo accept ip saddr @blocked_ips drop tcp dport { 22, 80, 443 } accept ip protocol icmp accept counter log prefix "DROPPED: " drop } chain forward { type filter hook forward priority filter; policy drop; } } ``` Применить: ```bash nft -f /etc/nftables.conf systemctl enable --now nftables ``` Преимущества по сравнению с firewalld: - **Atomic reload**, весь файл за одну транзакцию, без race-window - **Sets и maps**, нативно (vlan-id → action, ip → action) - **Один конфиг** в git, версионируемый - **Меньше абстракций**, что написал, то и в kernel - **Counters/log** инлайн, без дополнительной обвязки - **Меньше overhead**, нет daemon'а Недостатки: - Нет zones/services-абстракции, всё руками - Нет API для динамической перерисовки (каждое изменение, file edit + reload) - Сложнее для junior'ов ## Когда что выбрать **firewalld:** - Desktop / laptop с разными сетями (home/work/coffee-shop) - Multi-tenant сервер с зонами по доверию - RHEL прод, где админы привычны к firewall-cmd - Нужна интеграция с NetworkManager (NM zones) - Динамические правила через API/D-Bus от приложений **Чистый nftables:** - Server fleet с config-management (Ansible/Puppet) - Один конфиг для group of servers - Performance-чувствительные нагрузки (gateway, k8s-nodes) - Сложные rule-sets с sets/maps/vmaps - Кастомные NAT/mangle правила **iptables-legacy:** - Только если что-то старое не работает с nft - Docker до сих пор пишет правила через iptables, на нём оставляем **ufw:** - Простой случай "разрешить SSH, разрешить HTTPS, всё остальное drop" на одной машине; для большего, firewalld или nft ## Миграция firewalld → nft ```bash firewall-cmd --runtime-to-permanent # зафиксировать всё в XML systemctl stop firewalld systemctl disable firewalld systemctl mask firewalld nft list ruleset > /etc/nftables.conf # экспорт # Подчистить, добавить header, пропустить .data {}, .options {} systemctl enable --now nftables ``` Проверь, что всё открыто как было: `nft list ruleset`. ## firewalld backend toggle Можно временно вернуть iptables-backend если nft что-то ломает: ```ini # /etc/firewalld/firewalld.conf FirewallBackend=iptables # default, nftables ``` ```bash systemctl restart firewalld ``` Использовать только если конкретный кейс ломается на nftables-backend. ## Когда что-то пошло не так - **`firewall-cmd: not running`**, сервис не запущен. `systemctl start firewalld`. Проверь не masked ли (`systemctl unmask firewalld`). - **Изменения исчезают после reload**, забыл `--permanent`. - **`Service conflicts`**, другая firewall-утилита (iptables-services, ufw, nftables.service) уже живёт. Mask лишние. - **NAT не работает в external zone**, masquerade default включён только в external. В public, `firewall-cmd --zone=public --add-masquerade`. - **`nft: Could not process rule: No such file or directory`** syntax-error в конфиге; nftables-services не загружается. Проверь `nft -c -f /etc/nftables.conf` (dry-run). - **Docker сломался после nft restart**, Docker пишет свои правила в iptables/nft при старте. Перезапусти `systemctl restart docker` после firewall'а. - **Открыл порт, но не работает**, забыл `firewall-cmd --reload` после `--permanent`. Либо неправильная zone (проверь `--get-active-zones`). ## Сравнительная таблица | Признак | firewalld | nftables (чистый) | [cmd-iptables](/kb/cmd-iptables.md) | ufw | |---------|-----------|-------------------|------------------|-----| | Стиль | declarative XML + CLI | declarative file | imperative CLI | declarative CLI | | Backend | nftables (default) или iptables | nftables (kernel) | iptables (kernel xt_) | iptables | | Zones | да | нет | нет | нет | | Atomic reload | через restart | да | нет | нет | | Rich rules / DSL | rich-rules | nft DSL | shell-only | rules.before | | API / D-Bus | да | нет | нет | нет | | Runtime vs persistent | разделено | одно | руками `iptables-save` | одно | | Default в | RHEL/Fedora | Debian/Ubuntu modern | embedded, Alpine, legacy | Ubuntu desktop | | Сложность | средняя | низкая (если знаешь nft) | средняя | очень низкая | ## Команды ```bash firewall-cmd --list-all ``` Текущая зона и все её правила - первое что смотреть ```bash firewall-cmd --get-active-zones ``` Какие зоны активны и на каких интерфейсах/IP ```bash firewall-cmd --permanent --add-port=8080/tcp && firewall-cmd --reload ``` Открыть порт постоянно - типичный flow ```bash firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=1.2.3.4 reject' ``` Заблокировать конкретный IP через rich-rule ```bash nft list ruleset ``` Эффективное состояние kernel netfilter - неважно через что заведено ```bash nft -c -f /etc/nftables.conf ``` Dry-run nft-конфига перед применением - синтакс-чек без apply ```bash systemctl mask firewalld nftables iptables ``` Заблокировать конкурирующие firewall-сервисы - нельзя одновременно ## См. также - [nft - современный файрвол (nftables)](/kb/cmd-nft.md) - [iptables - правила netfilter (legacy)](/kb/cmd-iptables.md) - [NAT и masquerade](/kb/nat.md) - [IP forwarding - превратить хост в роутер](/kb/ip-forwarding.md) - [Conntrack - память Linux о всех сетевых соединениях](/kb/conntrack.md) - [CIS Benchmark и system hardening (lynis, OpenSCAP)](/kb/cis-benchmark-hardening.md)