Прямой ответ
Файрвол сервера начинается с принципа default-deny inbound: входящее запрещено всё, кроме явно разрешённого — это одна настройка, закрывающая класс проблем «забытая открытая база/админка торчит в интернет» (проверьте сейчас: ss -tlnp — что слушает сервер, и сравните с тем, что должно быть доступно снаружи — диагностика). Практический выбор инструмента: ufw — человеческий интерфейс для типового сервера (ufw default deny incoming; ufw allow 22,80,443/tcp; ufw enable — три минуты), под капотом тот же netfilter/nftables; nftables напрямую — когда нужен контроль: несколько таблиц, NAT, нестандартные цепочки, декларативный конфиг в ansible. Два самострела, которые нужно знать до enable: SSH-порт разрешён ДО включения (иначе удалённый доступ потерян — SSH-настройка); establ,related разрешены (иначе исходящие соединения ломают входящие ответы). И важное понимание границ: файрвол — про порты и адреса, не про уязвимости приложения (открытый 443 с дырявым приложением — дырявое приложение); но как гигиена периметра он обязателен: сканеры интернета находят открытый Postgres за минуты после подъёма сервера.
Модель netfilter: хуки, цепочки, состояния
Современный Linux-файрвол — nftables (пришёл на смену iptables; iptables-nft сегодня транслируется в nft-бэкенд). Механика: пакеты проходят хуки ядра (input — к локальным процессам, forward — транзит, output — исходящие), правила в таблицах/цепочках проверяются по порядку до первого совпадения; ключевая возможность — stateful-фильтрация: соединение отслеживается (ct state established,related accept — ответные пакеты разрешены автоматически), поэтому «default deny incoming» не ломает ваши исходящие запросы и их ответы. Практический словарь: iifname/oifname (входящий/исходящий интерфейс — правила для внутренней сети vs интернета), tcp dport (порт назначения), ip saddr (адрес источника — белые списки), counter (счётчик попаданий — диагностика «работает ли правило»). Понимание модели нужно даже при работе через ufw: ufw status verbose показывает те же цепочки, и «почему не работает» решается чтением правил, а не перебором команд.
ufw: минимум для рабочего сервера
Типовой веб-сервер за пять минут: ufw default deny incoming + ufw default allow outgoing (исходящее разрешено — сервер сам ходит в интернет за обновлениями/API); ufw allow 22/tcp (SSH — до enable, и если порт нестандартный — тот самый); ufw allow 80,443/tcp (веб); ufw enable (с подтверждением — предупреждение про обрыв SSH как раз об этом). Полезные дополнения: ufw allow from 10.8.0.0/24 to any port 5432 (Postgres только из VPN-подсети — WireGuard); ufw limit 22/tcp (rate-limit подключений — против перебора); ufw delete/ufw status numbered (правка списка — правила номеруются). Ограничения ufw: одна плоская таблица, сложные сценарии (несколько NAT, приоритеты, mark-маршрутизация) неудобны — потолок наступает быстро; но для 90% серверов «закрыть всё, открыть нужное» ufw закрывает полностью, а декларативность достигается ansible-ролью с ufw-правилами (конфиг в git, сервер воспроизводим).
nftables напрямую: таблицы и декларативность
Когда нужен контроль — прямой nft-конфиг (/etc/nftables.conf): table inet filter (inet = IPv4+IPv6 одной таблицей), chain input { type filter hook input priority 0; policy drop; ... } — политика drop и явные accept: established/related, loopback, ICMP (ping — не блокируйте: диагностика), SSH, HTTP(S). Пример логики белых списков: ip saddr { 10.8.0.0/24 } tcp dport 5432 accept — база из VPN; counter в правилах — видно, что срабатывает (nft list counter... — трафик по правилам). Применение: nft -f /etc/nftables.conf (атомарная загрузка — нет окна «правила наполовину применены»), systemd-юнит включает при старте. Важные практики: тестовая сессия — правки применять при живом втором подключении (или at-страховка: «через 5 минут перезагрузить файрвол в дефолт, если не отменил» — классика удалённой правки); версионирование конфига (файл в git через ansible — сервер восстанавливается с нуля прогоном); не смешивать ufw и ручные nft-правила без понимания (ufw управляет своими цепочками — ручные правки могут затираться; выбрать один инструмент на хост).
Практический сценарий: новый VPS и проверка периметра
Сервер поднят, на нём веб и Postgres. Шаг 1 — разведка: ss -tlnp показывает слушающие: sshd:22, nginx:80/443, postgres:5432 на 0.0.0.0 (!) — база наружу, классическая находка свежего сервера. Шаг 2 — решение по слоям: Postgres переводим на listen_addresses = 'localhost' (приложение на том же хосте — сетевой доступ не нужен вовсе) — это лучше любого файрвола; внешний доступ админа к базе — через VPN-подсеть. Шаг 3 — ufw: default deny incoming; allow 22 (проверено: SSH-сессия жива), 80, 443; allow from VPN-подсети на 5432 (на случай будущего отдельного приложения); enable. Шаг 4 — проверка снаружи: nmap -Pn -p 1-10000 IP с другой машины — открыты только 22/80/443 (сканирование себя изнутри обманчиво — проверять извне); ufw status verbose — правила на месте. Шаг 5 — фиксация: конфиг ufw в ansible-роль (инфраструктура), следующий сервер получает периметр автоматически; мониторинг — алерт на новый слушающий порт (скрипт-периодика или node_exporter-метрика). Контрнаходка сценария: на втором сервере забыт allow 22 перед enable — сессия выжила (established разрешён), но новые подключения не проходят — вход через консоль провайдера, правка; урок: порядок «сначала allow SSH» — не формальность.
FAQ
Firewall или security groups облака? Оба: security group/облачный файрвол фильтрует до виртуалки (удобен, централизован для флота), хостовый — защищает при ошибках конфигурации облака и переездах (сервер увезли из облака — правила уехали с ним). Двойной слой дешевле, чем разбор инцидента «кто-то открыл 0.0.0.0/0 в консоли».
Нужно ли фильтровать исходящий трафик? Для типового сервера — allow outgoing; для чувствительных контуров — да (сервер с веб-уязвимостью не сможет вынести данные/скачать пейлоад, если наружу разрешены только нужные адреса): исходящий default-deny с явным списком (DNS, обновления, API партнёров) — сильный барьер против эксфильтрации.
Заменит ли fail2ban файрвол? Нет, они ортогональны: файрвол — статические правила доступа; fail2ban — динамические баны по логам (SSH-статья). Файрвол первичен; fail2ban — дополнение там, где легитимный доступ открыт всем (веб, SSH).
Как отладить «правило есть, а не работает»?
Порядок: nft list ruleset — правило действительно загружено?; counter в правиле — растёт ли счётчик (нет — пакет не доходит/совпадает раньше другое правило: порядок важен); интерфейс/адрес в правиле совпадают с фактическими (ip a); после файрвола — приложение реально слушает (ss -tlnp) и не на 127.0.0.1.
Источники: wiki.nftables.org, документация Debian nftables, Ubuntu UFW — ссылки в шапке.