Почему файрвол - первый рубеж обороны Linux-сервера
Публичный IP-адрес начинают сканировать в первые минуты после появления в сети. Полный перебор 65535 TCP-портов занимает у автоматического сканера меньше минуты, а распределённые ботнеты проверяют десятки тысяч адресов параллельно. Сервер с открытым 22-м портом собирает от сотен до нескольких тысяч попыток входа в сутки. Файрвол отбрасывает этот трафик в ядре, до передачи данных приложению, поэтому CPU и диск не расходуются на обработку заведомо мусорных соединений.
Открытый порт даёт злоумышленнику готовый интерфейс к сервису. Redis на 6379 без пароля позволяет через CONFIG SET dir и dbfilename записать файл в произвольный каталог и положить свой SSH-ключ в /root/.ssh/authorized_keys. MongoDB на 27017 без аутентификации отдаёт содержимое всей базы. Docker API на 2375 разрешает запустить контейнер с примонтированным корнем хоста. Одно правило с policy drop закрывает все три сценария сразу.
Сервер за NAT тоже нуждается в фильтрации. Проброс портов на роутере часто шире, чем требуется: открыли 443 наружу, а заодно пробросили 8080 на отладочную панель. Конфигурация обратного прокси меняется, и внутренний сервис неожиданно начинает отвечать на внешнем интерфейсе. Файрвол на хосте ограничивает горизонтальное перемещение: получив доступ к одной машине, атакующий не подключится к PostgreSQL на соседней по 5432.
Отдельный сценарий, который почти всегда упускают, - исходящий трафик. Цепочка output по умолчанию разрешает всё, и вредонос, попавший на хост, свободно скачивает полезную нагрузку и отправляет украденные данные на управляющий сервер. Ограничение исходящих соединений по подсетям и портам сужает окно для атакующего заметно сильнее, чем один лишь фильтр входящих пакетов.
Выбор инструмента: nftables, iptables, ufw или firewalld
Четыре инструмента делят рынок, и три из них пишут правила в один движок ядра. Разница в уровне абстракции и в том, кто управляет цепочками: вы, демон или Docker.
| Инструмент | Уровень | Где применяется | Сильные стороны | Ограничения |
|---|---|---|---|---|
| nftables | подсистема ядра, Linux 3.13+ (2014) | Debian 10+, Ubuntu 20.04+, RHEL 8+, Arch, openSUSE | сеты и map, атомарная замена всего набора одной командой, единый синтаксис для IPv4, IPv6 и bridge | выше порог входа, чем у ufw |
| iptables | фронтенд xtables | старые скрипты и образы, RHEL 7 | огромное количество примеров и готовых решений | в RHEL 9, Debian 11+ и Ubuntu 20.04+ команда iptables ссылается на iptables-nft, старый движок остался как iptables-legacy |
| ufw | надстройка над nftables | Ubuntu, Debian, простые VPS | рабочий конфиг из четырёх команд, профили приложений, встроенный limit против брутфорса | не покрывает сложные задачи: сеты, mark, NAT, тонкие цепочки |
| firewalld | надстройка с зонами | RHEL, Fedora, CentOS Stream, Rocky, AlmaLinux | зоны, разделение runtime и permanent, rich rules, D-Bus API для автоматизации | зоны путают новичков, правила по умолчанию не переживают перезагрузку без runtime-to-permanent |
Практическое правило выбора: для нового сервера с веб-стеком берите nftables напрямую, если планируете сеты, NAT и логирование с лимитами; берите ufw, если нужен минимум правил и быстрый результат. В RHEL-семействе разумнее работать через firewalld: он использует backend nftables, и результат виден в nft list ruleset. iptables оставляйте там, где конфигурация уже написана, проверена и нет ресурса на миграцию. Подробные примеры для всех трёх инструментов собраны в материале о сравнении iptables, nftables и ufw, включая безопасную настройку по SSH без потери доступа.
Два инструмента одновременно не запускают. ufw и firewalld конфликтуют за цепочки, а Docker вставляет свои правила независимо от обоих. Проверьте, кто уже управляет набором правил, командой nft list ruleset и выводом systemctl status ufw firewalld.
Базовая политика deny all: пошаговая настройка
Схема одинакова для любого инструмента: политика по умолчанию drop, затем точечные разрешения. До первого запуска проверьте три вещи: на каком порту слушает SSH (ss -tlnp | grep sshd), есть ли доступ к консоли провайдера через VNC или KVM, установлены ли tmux или screen.
Откройте вторую SSH-сессию и не закрывайте её до конца работ. Поставьте отложенный откат правил на случай ошибки: echo "nft -f /etc/nftables.backup" | at now + 10 minutes. Простой способ быстро выйти из блокировки, если вы отрезали себя от сервера.
Настройка nftables с нуля
Файл /etc/nftables.conf с минимальным рабочим набором для веб-сервера:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state invalid drop
ct state established,related accept
iif lo accept
ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept
ip6 nexthdr ipv6-icmp accept
tcp dport { 22, 80, 443 } accept
ip saddr 10.0.0.0/24 tcp dport { 3306, 5432 } accept
limit rate 5/minute log prefix "nft-drop: " level warn
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
- flush ruleset очищает все таблицы, включая созданные Docker и fail2ban. На работающей системе сначала сохраните текущий набор: nft list ruleset > /root/nft-backup-$(date +%F).nft.
- ct state established,related accept пропускает ответные пакеты уже открытых сессий. Без этой строки перестанут работать исходящие запросы: ответы серверов не пройдут политику drop.
- iif lo accept нужен локальным сервисам, которые ходят друг к другу через loopback.
- ICMP: echo-request оставляет ping для диагностики, destination-unreachable и time-exceeded нужны для обнаружения MTU на пути. Полный запрет ICMP ломает часть сетевых сценариев.
- Сет { 22, 80, 443 } вместо трёх правил экономит проходы по цепочке: nftables проверяет набор за одно обращение.
- ip saddr 10.0.0.0/24 ограничивает базы данных внутренней подсетью. Порт 5432 наружу закрыт даже при работающем PostgreSQL.
- limit rate 5/minute log записывает отброшенные пакеты, не давая сканеру залить диск логами.
Применение и проверка синтаксиса выполняются двумя командами:
nft -c -f /etc/nftables.conf # проверка без применения nft -f /etc/nftables.conf # применение systemctl enable --now nftables nft list ruleset
Юнит nftables.service читает /etc/nftables.conf при загрузке, поэтому правила переживают перезагрузку. Для старого стека iptables потребуется пакет iptables-persistent и команда netfilter-persistent save.
Цепочка forward с политикой drop отключает транзит трафика. Если сервер работает шлюзом или публикует контейнеры с пробросом портов, понадобятся отдельные правила DNAT и FORWARD: эту часть разбирает руководство по маршрутизации и NAT в Linux.
Важная оговорка про Docker: опубликованный порт вида -p 8080:80 создаёт DNAT в таблице nat и попадает в цепочку DOCKER, минуя filter INPUT. Правило policy drop его не остановит. Публикуйте порты только на loopback (-p 127.0.0.1:8080:80) и проксируйте через Nginx, либо используйте ufw-docker для синхронизации цепочек.
Настройка ufw для типовых сервисов
Последовательность команд для Ubuntu или Debian:
sudo apt install ufw sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw limit 22/tcp sudo ufw enable sudo ufw status verbose
- default deny incoming задаёт политику drop для входящих, allow outgoing оставляет исходящие открытыми. Для строгого периметра политику output меняют на deny и разрешают нужные направления точечно.
- ufw limit 22/tcp включает встроенную защиту от брутфорса: адрес блокируется на время, если открывает больше 6 соединений за 30 секунд. Профиль OpenSSH подключается командой sudo ufw allow OpenSSH.
- IPv6 в ufw включён по умолчанию (IPV6=yes в /etc/default/ufw). Проверьте значение, иначе правила будут действовать только для IPv4.
Проверка состояния показывает правила вместе с политиками: sudo ufw status verbose и sudo ufw status numbered для удаления правил по номеру. Docker обходит ufw так же, как и nftables, по причине DNAT в цепочке DOCKER. Решения те же: ufw-docker или публикация портов только на 127.0.0.1.
Разрешение портов для баз данных: ограничение по IP
Порты 3306 (MySQL, MariaDB), 5432 (PostgreSQL), 6379 (Redis), 27017 (MongoDB), 9200 (Elasticsearch), 11434 (Ollama) не должны отвечать из публичной сети. Redis и MongoDB исторически лидируют по числу взломов из-за аутентификации, отключённой по умолчанию. С 2025 года сканеры активно ищут открытые эндпоинты инференса языковых моделей: чужой сервер бесплатно считает запросы неизвестных пользователей.
Правило для nftables внутри таблицы inet filter:
ip saddr 10.0.0.0/24 tcp dport { 3306, 5432, 6379 } accept
ip saddr 10.0.0.0/24 udp dport 6379 accept
Аналог для ufw:
sudo ufw allow from 10.0.0.0/24 to any port 5432 proto tcp sudo ufw allow from 10.0.0.0/24 to any port 6379 proto tcp
Ограничение по адресу надёжнее пароля, потому что отсекает попытки подбора до уровня приложения. Дополнительно закройте bind-address в конфигурации СУБД: для PostgreSQL параметр listen_addresses, для MySQL и MariaDB bind-address, для Redis bind и protected-mode yes. Если серверы живут в облаке, приватный интерфейс между ними и консольный доступ настраиваются на этапе создания: например, Timeweb Cloud выдаёт приватную сеть, трафик по которой не выходит в публичный сегмент, и VNC-консоль для аварийного доступа. Для распределённых команд альтернатива приватной сети - WireGuard: порт БД слушает только на интерфейсе туннеля.
Защита SSH от брутфорса с помощью fail2ban
Файрвол пропускает 22-й порт для всех адресов, поэтому подбор пароля продолжается на уровне демона SSH. fail2ban читает логи, находит серии неудачных входов и временно банит адрес правилом в файрволе.
Установка: sudo apt install fail2ban в Debian и Ubuntu, sudo dnf install fail2ban в RHEL и Fedora. Файл /etc/fail2ban/jail.conf редактировать не нужно: пакет перезапишет его при обновлении. Все изменения вносите в /etc/fail2ban/jail.local:
[DEFAULT] backend = systemd bantime = 1h findtime = 10m maxretry = 5 bantime.increment = true bantime.factor = 2 bantime.maxtime = 1w ignoreip = 127.0.0.1/8 ::1 203.0.113.10/32 [sshd] enabled = true port = ssh filter = sshd maxretry = 4 findtime = 10m
- bantime задаёт срок бана, findtime - окно, в котором считаются неудачные попытки, maxretry - их порог.
- bantime.increment = true с множителем factor удваивает срок при повторных нарушениях с того же адреса, maxtime ограничивает рост одной неделей. Повторный бан на час уже не помогает ботам.
- ignoreip защищает ваш адрес и адреса систем мониторинга. Ошибка в этом параметре приводит к самоблокировке: проверяйте его до перезапуска службы.
- backend = systemd читает журнал journald вместо файла /var/log/auth.log. В свежих сборках без rsyslog это единственный рабочий вариант.
- banaction по умолчанию в Debian и Ubuntu равен iptables-multiport, что на современных системах пишет правила через iptables-nft. На хосте с чистым nftables укажите banaction = nftables-multiport, при работе через ufw - banaction = ufw.
Проверка и управление:
sudo systemctl enable --now fail2ban sudo fail2ban-client status sudo fail2ban-client status sshd sudo fail2ban-client set sshd unbanip 203.0.113.77 sudo tail -f /var/log/fail2ban.log
Команда fail2ban-client status sshd показывает счётчик банов, список заблокированных адресов и файл журнала. Проверьте, что правила действительно появились в файрволе: nft list ruleset | grep f2b или iptables -L -n | grep f2b.
fail2ban закрывает подбор пароля, но не заменяет настройку самого SSH. Отключите вход по паролю (PasswordAuthentication no) и прямой вход root, оставив вход только по ключам. Остальные шаги по усилению демона и управлению sudo разобраны в материале о базовой безопасности сервера в 2026.
Аудит правил файрвола: чек-лист и тестирование
Аудит занимает 10-15 минут и отвечает на три вопроса: стоит ли политика drop на входе, нет ли лишних открытых портов, переживут ли правила перезагрузку.
- Выгрузите текущий набор: nft list ruleset, iptables -L -n -v, ufw status verbose, firewall-cmd --list-all. Для firewalld отдельно проверьте постоянные правила: firewall-cmd --list-all --permanent.
- Найдите строку политики: policy drop для nftables, Chain INPUT (policy DROP) для iptables, Default: deny (incoming) для ufw. Политика accept на входе обнуляет смысл остальных правил.
- Сверьте разрешённые порты со списком слушающих сокетов: ss -tulpn. Всё, что слушает 0.0.0.0 или :: и не должно быть публичным, переносите на 127.0.0.1 или закрывайте правилом.
- Проверьте IPv6 отдельно. Цепочка в таблице inet покрывает оба стека, а таблица ip6 filter их не видит: nft list table ip6 filter. Для iptables используйте ip6tables -L -n -v.
- Перезагрузите сервер и повторите шаг 1. Правила, живущие только в памяти, исчезают: для nftables нужен systemctl enable nftables, для iptables - пакет iptables-persistent с командой netfilter-persistent save, для firewalld - firewall-cmd --runtime-to-permanent.
- Проверьте цепочки fail2ban: они появляются после первого срабатывания фильтра. Пустая цепочка f2b при активном брутфорсе означает, что фильтр не читает журнал или указан неверный logpath.
- Отсканируйте периметр с внешнего хоста: nmap -sT -Pn -p- адрес_сервера. Сканирование выполняется только по своим системам или с письменного разрешения владельца инфраструктуры. Для быстрой проверки отдельного порта достаточно nc -zv адрес порт.
- Сравните результат сканирования с ожидаемым списком сервисов. Каждый лишний открытый порт - либо ошибка правила, либо сервис, который слушает слишком широко.
Проверка без риска для рабочей среды строится на трёх привычках. Первая: конфигурация хранится в git, перед применением выполняется синтаксическая проверка nft -c -f /etc/nftables.conf или ufw --dry-run. Вторая: изменения сначала тестируются на копии сервера в виртуалке или контейнере. Третья: держите открытой консоль провайдера и отложенный откат через at. Повторяйте аудит после каждого изменения инфраструктуры: новый сервис, новый контейнер, смена порта. Расширенный набор проверок и автоматический аудит уязвимостей через Lynis и OpenSCAP собраны в руководстве по hardening и аудиту Linux-сервера.
Логирование и мониторинг событий безопасности
Без журналов вы не узнаете, что ночью кто-то перебрал 40000 портов и получил три отказа в SSH. Логирование настраивается в том же инструменте, что фильтрует трафик.
Для nftables правило логирования ставится последним в цепочке, перед неявным drop:
limit rate 5/minute log prefix "nft-drop: " level warn limit rate 5/minute log prefix "nft-drop: " level warn tcp flags syn log flags all
Записи уходят в кольцевой буфер ядра, оттуда в journald и rsyslog. Смотреть их удобно так: journalctl -k -f, dmesg -w, grep nft-drop /var/log/kern.log. Для отдельного файла нужен ulogd2 с плагином NFLOG, который принимает пакеты логирования по netlink.
Для ufw логирование включается командой sudo ufw logging on (уровни low, medium, high), записи попадают в /var/log/ufw.log. Для iptables цель LOG ставится до DROP, потому что LOG не завершает обработку пакета:
iptables -A INPUT -j LOG --log-prefix "iptables-drop: " --log-level 4 iptables -A INPUT -j DROP
- fail2ban пишет в /var/log/fail2ban.log: срабатывания фильтров, баны, разбаны. Настройте logrotate для этого файла, иначе при активном сканировании он вырастет до гигабайтов за неделю.
- Оповещения строятся на счётчиках: fail2ban-client status sshd, число записей nft-drop за час, всплеск кодов 401 и 403 в логах Nginx. Пороговые значения отправляйте в систему мониторинга.
- Анализ веб-логов удобно вести через goaccess: он разбирает access.log и показывает источники подозрительного трафика.
Логирование с лимитом обязательно. Одна сканирующая подсеть генерирует десятки тысяч отброшенных пакетов в минуту, и запись каждого из них загружает диск и процессор сильнее, чем сама фильтрация. Для разбора больших выгрузок можно подключить языковую модель через API: AiTunnel даёт единый ключ к десяткам моделей с оплатой в рублях, и скрипт отправляет подозрительные строки на суммаризацию вместо ручного просмотра.
Типичные ошибки при настройке файрвола и как их избежать
- deny all до проверки SSH-порта. Политика drop применяется мгновенно, и доступ теряется вместе с сервером. Решение: вторая сессия, консоль провайдера и отложенный откат командой at.
- Неверный порядок правил. В nftables и iptables правила проверяются сверху вниз, первое совпадение определяет судьбу пакета. Правило drop, поставленное выше разрешающего, блокирует нужный сервис. Логирующее правило оставляйте последним.
- Правила не сохраняются после перезагрузки. Для nftables нужен systemctl enable nftables, для iptables - netfilter-persistent save, для firewalld - firewall-cmd --runtime-to-permanent. Правило, добавленное через --permanent без reload, не работает до перезапуска службы.
- Конфликт с Docker. Контейнер, опубликованный как -p 8080:80, доступен из интернета даже при policy drop, потому что DNAT выполняется в таблице nat до фильтрации на входе. Решения: ufw-docker, публикация на 127.0.0.1 с обратным прокси, отключение iptables у демона Docker с ручным описанием правил.
- Открытые порты баз данных. MySQL, PostgreSQL, Redis и MongoDB не должны отвечать из публичной сети никогда. Ограничение по ip saddr или from в ufw закрывает вектор целиком.
- Забытый IPv6. Многие VPS получают IPv6 по умолчанию, сервисы слушают на ::, а правила написаны только для IPv4. Проверяйте ss -tulpn и таблицу ip6.
- Нет журналов и оповещений. Файрвол без логов молча отбрасывает атаки, и о компрометации узнают от провайдера. Логирование с лимитом и счётчики банов закрывают этот пробел.
- Самоблокировка fail2ban. Офисный NAT-адрес или адрес VPN легко попадает под бан при опечатке в пароле. ignoreip с вашей подсетью и адресом мониторинга обязателен.
- Смена порта SSH без правки правил. Перенос демона на нестандартный порт без обновления набора правил отрезает доступ. Меняйте порт и правило одним окном обслуживания.
- flush ruleset в проде. Команда стирает все таблицы, включая цепочки Docker, fail2ban и NAT. Перед ручной правкой сохраняйте снимок: nft list ruleset > backup.nft.
Ещё одна ошибка встречается реже, но стоит дороже остальных: приложение слушает на 0.0.0.0 при том, что правило разрешает доступ только доверенной подсети. Файрвол спасает до первой ошибки в правилах, поэтому bind на 127.0.0.1 оставляйте вторым слоем защиты. Полный набор политик по доступу, sudo и мандатному контролю разобран в руководстве по политике безопасности Linux-сервера.
Что изменилось в 2026 году: актуальные рекомендации
nftables стал стандартом де-факто: он используется в Ubuntu 20.04 и новее, Debian 10 и новее, RHEL 8 и новее, openSUSE. В RHEL 9 и Ubuntu команда iptables ссылается на iptables-nft, а старый движок остался только как iptables-legacy в устаревших образах. Новые возможности появляются именно в nftables: именованные сеты, verdict maps, динамическое наполнение наборов из скриптов.
firewalld версии 2.x работает поверх nftables и добавил политики (policies) для описания правил между зонами, что упрощает сегментацию хоста с несколькими сетевыми интерфейсами. fail2ban 1.1 закрывает типовые задачи защиты SSH. Как альтернатива набирает популярность CrowdSec: сценарии в виде collections, обмен репутацией адресов между установками и бан через bouncer на уровне nftables.
Сместились и цели атак. Кроме Redis, MongoDB и Docker API на 2375, сканеры массово ищут открытые панели управления и эндпоинты инференса моделей на 11434. В Kubernetes защита узла не покрывает поды: трафик между ними идёт по overlay-сети и не проходит через filter INPUT хоста. Эту зону закрывают NetworkPolicy и CNI с реализацией на eBPF, например Cilium, а классические правила хоста остаются защитой самого узла и его служебных портов.
Управление правилами переходит в код. Набор из /etc/nftables.conf хранится в git, проверяется в CI командой nft -c -f, применяется через Ansible (community.general.ufw, ansible.posix.firewalld) или Terraform-провайдеры облака. Откат на предыдущую версию занимает одну команду, и это снимает главный страх при работе с периметром продакшена.
Начните с двух действий сегодня: выгрузите текущий набор правил в git (nft list ruleset > rules.nft) и сверьте его с выводом ss -tulpn. Это даст реальную картину периметра быстрее, чем любая теория, и покажет, какие порты закрывать первыми.