SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-13

Настройка firewalld в Rocky Linux и AlmaLinux

Узнайте, как открывать порты SSH и HTTP, закрывать доступ и применять правила через --permanent. Инструкция по работе с зонами для сохранения настроек после перезагрузки сервера.

Что такое firewalld и почему он поставляется в Rocky и AlmaLinux

firewalld — это менеджер межсетевого экрана, установленный по умолчанию в Rocky Linux, AlmaLinux и других дистрибутивах, основанных на Red Hat Enterprise Linux (RHEL). Он не занимается проверкой пакетов напрямую. Он хранит конфигурацию и преобразует её в правила nftables. Одна команда, firewall-cmd, позволяет изменять настройки без остановки работы сервера.

Если вы уже знаете, как работает ufw на Ubuntu VPS, то понимаете суть задачи. firewalld добавляет две концепции, которых нет в ufw. Первая — это зоны: именованные политики, по которым распределяются пакеты. Вторая — разделение между текущими правилами и сохранёнными настройками, что регулируется флагом --permanent и является главным источником путаницы при работе с этим инструментом.

Все приведённые ниже команды выполняются на вашем сервере. Проверяйте каждое изменение с другого компьютера, так как правило, которое выглядит корректным локально, может оказаться ошибочным при доступе из Интернета.

Откройте SSH перед выполнением любых других действий

В большинстве дистрибутивов Rocky и AlmaLinux пакет firewalld уже установлен и запущен, а стандартная конфигурация разрешает SSH. Некоторые минимальные облачные образы исключают его. Проверяйте состояние, а не полагайтесь на предположения.

sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --state

firewall-cmd --state выводит running. Если служба остановлена, любой другой вызов firewall-cmd возвращает FirewallD is not running и завершается с ненулевым кодом. Это первое, что нужно проверить, если команда кажется невыполненной.

Теперь ознакомьтесь с текущими правилами.

sudo firewall-cmd --list-all

Реальный вывод содержит еще несколько строк. Важны следующие:

public (active)
  target: default
  interfaces: eth0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  rich rules:

ssh в строке services: — причина, по которой ваша сессия всё еще активна. Если этого правила нет, добавьте его перед любыми другими изменениями. Запуск межсетевого экрана без правила для SSH прервет сессию и заблокирует доступ к серверу.

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

target: default означает, что пакет, не соответствующий ни одному правилу, отклоняется с ответом ICMP (internet control message protocol) host-prohibited. В результате клиент, обращающийся к закрытому порту, немедленно получает No route to host. Установка цели в DROP делает сервер «невидимым», и сканеры будут ожидать истечения времени ожидания (timeout).

sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reload

Учитывайте последствия перед выполнением этой команды: DROP также запрещает серверу отвечать на ping, поэтому ваш мониторинг перестанет получать данные.

Почему мое правило исчезло? Флаг --permanent

firewalld хранит две конфигурации одновременно. Runtime-конфигурация — это то, что ядро применяет в данную секунду. Permanent-конфигурация — это то, что находится в /etc/firewalld/zones/public.xml и восстанавливается после перезагрузки службы или системы.

Команда без --permanent изменяет только runtime-конфигурацию. Она работает немедленно, но настройки пропадают после перезагрузки. Команда с --permanent записывает изменения в файл, но не меняет текущее состояние, поэтому порт останется закрытым до выполнения reload. Оба поведения не являются ошибкой. Они часто удивляют пользователей, так как команда в обоих случаях выводит success.

Всегда используйте обе команды в паре.

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload

Вы можете просмотреть обе конфигурации — это самый быстрый способ понять, какую из двух ошибок вы допустили.

sudo firewall-cmd --list-services
sudo firewall-cmd --permanent --list-services

Первая команда выводит текущий набор правил. Вторая — сохраненный набор. Если в текущем наборе есть служба, которой нет в сохраненном, правило исчезнет после следующего reload. Если в сохраненном наборе есть служба, которой нет в текущем, вы забыли выполнить reload. sudo firewall-cmd --runtime-to-permanent копирует все текущие настройки в файл конфигурации, что полезно после сеанса экспериментов.

--reload сохраняет состояние отслеживания соединений, поэтому ваша SSH-сессия не прервется. --complete-reload также перезагружает модули ядра и сбрасывает это состояние, что обычно приводит к разрыву всех открытых соединений, включая ваше. Используйте обычный reload.

В систему встроен механизм защиты. Runtime-правило может истечь автоматически.

sudo firewall-cmd --add-service=http --timeout=5m

Это правило удалится само через пять минут. Его нельзя использовать вместе с --permanent, и в этом смысл: оно существует для тестирования изменений, в которых вы не уверены. Более старый метод защиты надежнее. Держите вторую SSH-сессию открытой во время редактирования правил и не закрывайте ее, пока не убедитесь, что новые правила работают, успешно выполнив вход в систему.

Зоны и почему на VPS важна только зона по умолчанию

Зона — это именованный набор разрешений с определенным уровнем доверия. firewalld помещает каждый входящий пакет ровно в одну зону. Сначала он сопоставляет исходный адрес пакета со списком sources: каждой зоны. Если совпадений нет, используется зона, к которой привязан входящий интерфейс. Если интерфейс не привязан ни к одной зоне, пакет попадает в зону по умолчанию.

sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones

На VPS с одним сетевым интерфейсом ответом почти всегда будет public, и это единственная зона, которую вы будете использовать. firewall-cmd без аргумента --zone= применяется к зоне по умолчанию, поэтому каждая короткая команда в этом руководстве работает без указания имени зоны.

Вот ошибка, на которую можно потратить весь день. Если интерфейс привязан к другой зоне, ваши правила попадают в public, в то время как трафик обрабатывается в другом месте. В результате добавленные правила не действуют, а система не выдает никаких предупреждений. --get-active-zones показывает привязку:

public
  interfaces: eth0

Если интерфейс отображается в другой зоне, либо записывайте правила в эту зону с помощью --zone=, либо переместите интерфейс.

sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reload

NetworkManager управляет интерфейсами в Rocky и AlmaLinux, и он восстанавливает зону при поднятии соединения. Установите зону там, чтобы перезагрузка не отменила ваши настройки. Имя соединения возьмите из первой команды, так как оно редко совпадает с именем устройства.

sudo nmcli connection show
sudo nmcli connection modify "System eth0" connection.zone public

Сопоставление по источнику имеет приоритет над сопоставлением по интерфейсу, что позволяет применять разные политики для одного адреса. Встроенная зона trusted принимает всё.

sudo firewall-cmd --permanent --zone=trusted --add-source=203.0.113.10/32
sudo firewall-cmd --reload

Будьте осторожны с этой зоной. Она открывает для указанного адреса все порты на сервере, включая базу данных, которую вы считали защищенной. Используйте rich rule, если хотите открыть один порт, а не весь хост.

Что такое служба в firewalld?

Служба — это именованный набор портов, оформленный в виде XML-файла. --add-service=https открывает 443/tcp, потому что /usr/lib/firewalld/services/https.xml определяет, что именно означает https.

sudo firewall-cmd --get-services
sudo firewall-cmd --info-service=https

--info-service выводит список портов, скрывающихся за этим именем:

https
  ports: 443/tcp

Используйте имя службы, если оно существует. Это упрощает чтение конфигурации в --list-all спустя полгода, а такие пакеты, как Cockpit, устанавливают собственные файлы служб. Используйте --add-port для всего, для чего нет готового определения.

Важный нюанс: служба ssh означает только 22/tcp и ничего больше. Если вы перенесли SSH на другой порт в процессе укрепления безопасности SSH на сервере, то --add-service=ssh не откроет порт, который вы используете на самом деле.

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

В дистрибутивах на базе RHEL существует дополнительный уровень защиты. SELinux (security-enhanced Linux) присваивает метки номерам портов, и sshd не может привязаться к порту, который не соответствует его меткам. В этом случае служба отказывается запускаться, а в логах появляется сообщение error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Сначала необходимо назначить порту соответствующую метку.

sudo dnf install -y policycoreutils-python-utils
sudo semanage port -a -t ssh_port_t -p tcp 2222

Как узнать, какие порты открыты в данный момент?

sudo firewall-cmd --list-all
sudo firewall-cmd --list-rich-rules
sudo nft list table inet firewalld | head -n 40

Первые две команды показывают состояние, которое считает верным firewalld. Третья команда считывает правила, которые фактически загружены в ядро в таблице, принадлежащей firewalld. Эти данные должны совпадать.

Ни один из этих методов не является доказательством. Проведите проверку с другого компьютера:

nc -zv 203.0.113.20 443

Не запускайте тест на самом сервере. firewalld разрешает любые соединения, поступающие через интерфейс loopback, поэтому curl http://localhost:8080 будет успешным независимо от ваших правил. Этот тест лишь подтверждает, что сервис запущен. Он не дает никакой информации о работе межсетевого экрана.

Разрешение веб-порта

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

После выполнения последней команды в списке должна появиться запись http https наряду с уже имевшимися там ранее. Если сайт по-прежнему не отвечает, проблема, вероятно, не в межсетевом экране. Правило лишь разрешает прохождение пакета. Процесс всё ещё должен ожидать соединение на этом порту.

sudo ss -tlnp

Сокет, отображаемый как 0.0.0.0:443 или *:443, принимает соединения с любого адреса. Сокет, отображаемый как 127.0.0.1:443, отвечает только на loopback-интерфейсе, и никакое правило межсетевого экрана не сделает его доступным извне. В статье Порты и слушающие сокеты в Linux эта разница описана более подробно.

Как снова закрыть порт?

sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reload

Правило --permanent применимо и здесь, причем в этом направлении оно работает строже. Если удалить сервис только из текущего сеанса, порт будет выглядеть закрытым, но после перезагрузки или перезапуска конфигурации он снова откроется, так как настройки будут считаны из файла. Это уязвимость, которую легко пропустить, так как проверка после удаления покажет успех.

Удаление несуществующего правила выводит Warning: NOT_ENABLED: http, но завершается с кодом 0. Повторное добавление того же правила выводит Warning: ALREADY_ENABLED: http. Оба действия безопасны. Ошибка в имени сервиса приводит к иному результату: Error: INVALID_SERVICE означает, что в firewalld нет определения с таким именем и изменения не были внесены.

Если команда --list-all показывает cockpit, а вы не используете веб-консоль Cockpit на порту 9090, удалите её. Каждый открытый порт — это сервис, который требует своевременного обновления и обслуживания.

Ограничение доступа к порту для одного IP-адреса

Rich rules — это расширенный синтаксис, который используется, когда стандартного имени сервиса недостаточно для описания задачи. Чтобы ограничить доступ к SSH одним офисным адресом, нужно выполнить две команды; вторую из них часто забывают.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

Зона — это набор правил, а не нумерованный список, работающий до первого совпадения. Rich rule добавляет разрешение для одного адреса, но не запрещает доступ остальным. Пока ssh находится в строке services:, весь интернет по-прежнему имеет доступ к 22 порту, и rich rule не меняет ситуацию. Удалите общее правило, иначе узкое ограничение будет бесполезным.

Если у порта нет имени сервиса, укажите номер порта напрямую.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port port="5432" protocol="tcp" accept'

Чтобы отбросить пакеты от «шумной» сети и сохранить запись об этом, поместите элемент log перед действием — именно такой порядок ожидает синтаксис rich rules.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" log prefix="fw-drop " level="info" limit value="3/m" drop'
sudo firewall-cmd --reload
sudo journalctl -k -g fw-drop

Значение limit предотвращает переполнение журнала потоком пакетов. Прежде чем ограничивать SSH одним адресом, убедитесь, что этот адрес стабилен. Домашнее подключение с динамическим IP-адресом заблокирует вам доступ в день смены адреса, поэтому сначала проверьте работоспособность консольного доступа, предоставляемого вашим провайдером.

Команды ufw и их эквиваленты в firewall-cmd

Одни и те же задачи, разные инструменты. Каждая строка --permanent требует добавления sudo firewall-cmd --reload, чего нельзя показать в простом списке.

  • sudo ufw enable заменяется на sudo systemctl enable --now firewalld
  • sudo ufw disable заменяется на sudo systemctl disable --now firewalld
  • sudo ufw status verbose заменяется на sudo firewall-cmd --list-all
  • sudo ufw allow OpenSSH заменяется на sudo firewall-cmd --permanent --add-service=ssh
  • sudo ufw allow 443/tcp заменяется на sudo firewall-cmd --permanent --add-port=443/tcp
  • sudo ufw delete allow 443/tcp заменяется на sudo firewall-cmd --permanent --remove-port=443/tcp
  • sudo ufw allow from 203.0.113.10 to any port 22 заменяется на rich rule, показанное выше
  • sudo ufw reload заменяется на sudo firewall-cmd --reload
  • sudo ufw default deny incoming — это стандартное поведение зоны public, а --set-target=DROP — его «тихая» версия
  • sudo ufw logging on заменяется на sudo firewall-cmd --set-log-denied=all

Стоит чётко отметить одно различие. ufw поддерживает нумерованный список, что позволяет вставить правило на позицию 1. В firewalld нет номеров правил, поэтому команда «поставить это правило первым» не имеет смысла. Если две записи в firewalld противоречат друг другу, приоритет получает разрешающее правило, так как в наборе нет явных запретов. Широкое правило необходимо удалять вручную.

Почему мой Docker-контейнер доступен, хотя файрвол выглядит закрытым?

Потому что опубликованный порт контейнера не попадает в ту часть файрвола, которую контролирует ваша зона. docker run -d -p 8080:80 nginx указывает Docker записывать собственные правила NAT (network address translation) и пересылки. Пакет, приходящий на 8080, перезаписывается и направляется в контейнер, поэтому он пересылается, а не доставляется на хост. Строки services: и ports: в вашей зоне управляют пакетами, доставляемыми на хост. Правила Docker управляют путем пересылки, и они разрешают трафик.

В результате получается сервер, где sudo firewall-cmd --list-all не показывает порт 8080, а nc -zv 203.0.113.20 8080 с другой машины всё равно устанавливает соединение. Посмотрите, что установил Docker:

sudo iptables -t nat -L DOCKER -n

Решение заключается в использовании флага публикации. Привяжите порт к loopback-интерфейсу и поставьте перед ним reverse proxy.

docker run -d -p 127.0.0.1:8080:80 nginx

Теперь контейнер отвечает на curl http://127.0.0.1:8080 только на самом сервере, а извне — нет. Пользователи Ubuntu сталкиваются с той же проблемой, описанной в почему Docker-контейнеры публикуют порты в обход ufw. Podman с правами root, который поставляется в базовых репозиториях Rocky и AlmaLinux, публикует порты с использованием того же подхода NAT, поэтому проводите тестирование с другой машины, а не доверяйте списку зоны.

Обеспечение автозапуска после перезагрузки и типичные ошибки

sudo systemctl is-enabled firewalld
sudo systemctl status firewalld

enabled и active (running) — это именно те команды, которые вам нужны. Запущенный, но не добавленный в автозагрузку межсетевой экран защищает сервер только до первой перезагрузки. Эту проверку следует включить в список обязательных действий из раздела первые десять минут на новом VPS, наряду с настройкой SSH-ключей и обновлением системы.

Прямые команды nftables и firewalld несовместимы. firewalld управляет таблицей с именем inet firewalld. Команда sudo nft flush ruleset удаляет её, после чего сервер становится полностью открытым для внешних подключений, а firewall-cmd --list-all продолжает выводить вашу конфигурацию, так как firewalld сообщает о своих намерениях, а не о текущем состоянии ядра. Команда sudo firewall-cmd --reload восстанавливает правила. Записывайте правила с помощью firewall-cmd, чтобы они сохранялись после перезагрузки.

Два менеджера межсетевого экрана на одном сервере. Установка ufw или iptables-services параллельно с firewalld приводит к тому, что две программы создают правила, не зная о существовании друг друга. Победит та, что запустилась последней. Выберите что-то одно. В дистрибутивах Rocky и AlmaLinux предпочтительным является firewalld, так как он поддерживается на уровне системы.

Сетевой экран провайдера перед сервером. Многие панели управления VPS имеют собственный сетевой экран. Если --list-all показывает, что порт открыт, а подключение извне всё равно не проходит, проверьте настройки панели, прежде чем менять что-либо на сервере. Это работает и в обратную сторону: правило в панели не даст результата, если firewalld отбрасывает пакет.

Запуск firewall-cmd без sudo. Любое изменение требует прав root. Без них запрос отклоняется системой авторизации, и ничего не меняется, что на первый взгляд выглядит так, будто команда была проигнорирована.

Шесть команд покрывают большинство повседневных задач: --list-all для проверки состояния, --permanent --add-service или --add-port для открытия порта, --permanent --remove-service для его закрытия, --reload для применения сохранённого файла и --runtime-to-permanent после серии экспериментов. Зона по умолчанию — public, флаг — --permanent, а единственная достоверная проверка выполняется с другого компьютера.

FAQ

Почему моё правило firewalld исчезло после перезагрузки?

Правило было добавлено только в текущую конфигурацию (runtime). sudo firewall-cmd --add-service=http применяется немедленно, но сбрасывается при следующей перезагрузке или обновлении конфигурации, так как сохранённый файл /etc/firewalld/zones/public.xml не был изменён. Добавьте --permanent, а затем выполните sudo firewall-cmd --reload. Чтобы сохранить правила, которые вы уже добавили вручную, выполните sudo firewall-cmd --runtime-to-permanent: эта команда копирует текущий набор правил в файл постоянной конфигурации.

Почему ничего не меняется после добавления правила с флагом --permanent?

Потому что --permanent записывает данные в файл, не затрагивая работающий межсетевой экран. Порт остаётся закрытым, пока sudo firewall-cmd --reload не загрузит сохранённую конфигурацию в ядро. Сравните вывод sudo firewall-cmd --list-services и sudo firewall-cmd --permanent --list-services: если в сохранённом списке есть запись, которой нет в текущем, значит, вы забыли выполнить перезагрузку конфигурации.

Что лучше использовать: --add-service или --add-port?

Используйте --add-service, если для вашего приложения существует предопределённое имя сервиса. Это отражает намерение администратора, а sudo firewall-cmd --info-service=https позволяет увидеть, какие именно порты открывает это имя. Используйте --add-port, если ваш сервис не описан в системе или работает на нестандартном порту. Сервис ssh открывает только 22/tcp, поэтому для SSH, перенесённого на 2222 порт, потребуется --add-port=2222/tcp и соответствующая метка SELinux для этого порта.

Почему мой Docker-контейнер доступен извне, хотя firewall-cmd показывает, что порт закрыт?

Опубликованный порт перенаправляется правилами NAT самого Docker напрямую в контейнер. Пакет не доставляется хостовой системе, а списки сервисов и портов в зоне относятся только к пакетам, адресованным самому хосту. Контейнер отвечает на запросы из сети, в то время как --list-all не показывает открытых портов. Привязывайте порты к loopback-интерфейсу с помощью docker run -d -p 127.0.0.1:8080:80 nginx и используйте перед контейнером reverse proxy.

Можно ли установить ufw на Rocky Linux вместо firewalld?

Два менеджера межсетевого экрана на одном сервере создают конфликтующие правила, не зная о действиях друг друга. Итоговый результат зависит от того, какой сервис запустился последним. firewalld — это штатный инструмент для Rocky Linux и AlmaLinux; он уже установлен и управляет тем же бэкендом nftables, который использовал бы ufw. Изучите работу зон по умолчанию и флаг --permanent — этого достаточно для полноценного управления инструментом.