firewalld на Rocky та AlmaLinux: базове налаштування VPS
Відкрийте SSH і web-порт, закрийте непотрібний порт та збережіть правила після перезавантаження. Пояснюємо зони й пастку прапорця --permanent.
Що таке firewalld і чому Rocky та AlmaLinux постачаються з ним
firewalld — це менеджер firewall, встановлений за замовчуванням у Rocky Linux, AlmaLinux та інших збірках Red Hat Enterprise Linux (RHEL). Обидва дистрибутиви успадкували це налаштування, а не обирали його самостійно. Це зрозуміліше, якщо ви знаєте як Rocky та AlmaLinux почали відтворювати роботу Red Hat після зміни напрямку розвитку CentOS. firewalld не перевіряє пакети самостійно. Він зберігає конфігурацію та перетворює її на правила nftables. Одна команда, firewall-cmd, змінює цю конфігурацію, поки сервер залишається доступним. У цьому посібнику нічого не відрізняється для цих двох дистрибутивів, оскільки те, що фактично відрізняє Rocky від AlmaLinux, — це гарантії сумісності та діапазон підтримуваних процесорів, а не firewall.
Якщо ви вже знаєте як працює ufw на Ubuntu VPS, то розумієте його призначення. firewalld додає дві концепції, яких немає в ufw. Перша — це зони: іменовані політики, до яких розподіляються пакети. Друга — розділення активних і збережених правил. Для цього використовується прапорець --permanent, який є головним джерелом плутанини в цьому інструменті.
Усе нижче — це команди, які ви виконуєте на власному сервері. Перевіряйте кожну зміну з другого комп’ютера, оскільки правило, яке виглядає правильним на сервері, усе одно може бути неправильним під час доступу з інтернету.
Відкрийте SSH перед будь-якими іншими діями
У більшості інсталяцій Rocky та AlmaLinux firewalld уже встановлено й запущено, а конфігурація, що постачається із системою, дозволяє SSH. У деяких мінімальних cloud-образах firewalld видалено. Перевірте це, а не робіть припущень.
sudo dnf install -y firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --statefirewall-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: дає змогу вашій сесії продовжувати працювати. Якщо цього правила немає, додайте його, перш ніж робити будь-що інше, оскільки запуск firewall без правила для SSH завершить сесію і не дасть підключитися знову.
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadtarget: default означає, що пакет, який не відповідає жодному правилу, відхиляється з відповіддю ICMP (internet control message protocol) host-prohibited, тому клієнт, який звертається до закритого порту, одразу отримує No route to host. Якщо встановити target у DROP, сервер натомість не відповідатиме, і сканери чекатимуть на тайм-аут.
sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reloadПерш ніж виконувати цю команду, врахуйте наслідки: DROP також припиняє відповіді сервера на ping, тому ваш власний моніторинг теж перестане працювати.
Чому моє правило зникло? Прапорець --permanent
firewalld одночасно зберігає дві конфігурації. Конфігурація runtime — це правила, які kernel застосовує зараз. Постійна конфігурація зберігається в /etc/firewalld/zones/public.xml і відновлюється після reload або reboot.
Команда без --permanent змінює лише runtime-конфігурацію. Зміни застосовуються одразу, але зникають під час наступного reload або boot. Команда з --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 також перезавантажує kernel modules і втрачає цей стан, через що зазвичай розриваються всі відкриті з’єднання, зокрема ваш сеанс. Використовуйте звичайний 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 --reloadNetworkManager керує інтерфейсами в Rocky та AlmaLinux і повторно застосовує зону під час активації підключення. Установіть цю прив’язку також у NetworkManager, щоб перезавантаження не скасувало внесені зміни. Назву підключення візьміть із першої команди, оскільки вона рідко збігається з назвою пристрою.
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.
Що таке service у firewalld?
Service — це іменований набір портів, описаний у 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 також встановлюють власні service-файли. Використовуйте --add-port для всього, для чого немає визначення.
Зверніть увагу на важливе обмеження: service 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 виконується незалежно від ваших правил. Ця перевірка показує, що сервіс працює. Вона нічого не повідомляє про firewall.
Дозвольте вебпорт
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. Якщо сайт і далі не відповідає, проблема може бути не у firewall. Правило дозволяє пакет. Процес усе одно має прослуховувати цей порт.
sudo ss -tlnpСокет, показаний як 0.0.0.0:443 або *:443, приймає з’єднання з будь-якої адреси. Сокет, показаний як 127.0.0.1:443, відповідає лише через loopback, і жодне правило firewall не зробить його доступним ззовні. У матеріалі Порти та сокети, що прослуховуються, у 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, видаліть цей сервіс. Кожен відкритий порт відповідає сервісу, який потрібно своєчасно оновлювати. Для сервісів, які ви вирішили залишити, dnf-automatic може встановлювати оновлення безпеки за розкладом, щоб цей процес не залежав від того, чи згадаєте ви про нього. Однак встановлення оновлення не означає його застосування, і needs-restarting показує, які сервіси все ще використовують старі бібліотеки після встановлення цих оновлень.
Обмеження порту для однієї 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 firewalldsudo ufw disableстаєsudo systemctl disable --now firewalldsudo ufw status verboseстаєsudo firewall-cmd --list-allsudo ufw allow OpenSSHстаєsudo firewall-cmd --permanent --add-service=sshsudo ufw allow 443/tcpстаєsudo firewall-cmd --permanent --add-port=443/tcpsudo ufw delete allow 443/tcpстаєsudo firewall-cmd --permanent --remove-port=443/tcpsudo ufw allow from 203.0.113.10 to any port 22стає rich rule, наведеною вищеsudo ufw reloadстаєsudo firewall-cmd --reloadsudo ufw default deny incoming— це вже поведінка зониpublic, а--set-target=DROP— її безшумний варіантsudo ufw logging onстаєsudo firewall-cmd --set-log-denied=all
Є одна важлива відмінність. ufw зберігає нумерований список, і правило можна вставити на позицію 1. У firewalld номерів правил немає, тому вислів «поставити це правило першим» тут не має сенсу. Якщо два записи firewalld, на перший погляд, суперечать один одному, перевагу має широке правило accept, оскільки в наборі немає правила deny. Широкий запис потрібно видалити вручну.
Чому мій Docker-контейнер доступний, хоча брандмауер, схоже, закритий?
Тому що опублікований порт контейнера не проходить через ту частину брандмауера, якою керує ваша зона. docker run -d -p 8080:80 nginx вказує Docker створити власні правила NAT (перетворення мережевих адрес) і пересилання. Пакет, що надходить на 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. Rootful Podman, який Rocky і AlmaLinux постачають у базових репозиторіях, публікує порти за тим самим підходом NAT, тому перевіряйте доступ з іншої машини, а не покладайтеся на список зони. Саме через це встановлення Docker Engine у цих дистрибутивах потребує кількох кроків, про які в посібнику для Ubuntu не згадують, починаючи з того, що Podman уже використовує команду docker.
Як пережити перезавантаження та які помилки ви побачите
sudo systemctl is-enabled firewalld
sudo systemctl status firewalldenabled і active (running) — саме те, що потрібно. Запущений, але не увімкнений firewall захищає сервер лише до першого перезавантаження. Цю перевірку слід додати до списку дій, які ви виконуєте у перші десять хвилин на новому VPS, разом із налаштуванням SSH-ключів і встановленням оновлень.
Не змішуйте raw-команди nftables і firewalld. firewalld володіє таблицею з назвою inet firewalld. Команда sudo nft flush ruleset видаляє її, після чого сервер стає відкритим для всього трафіку. Водночас firewall-cmd --list-all і далі виводить потрібну вам конфігурацію, оскільки firewalld показує те, що він вважає актуальним, а не те, що зберігає kernel. Команда sudo firewall-cmd --reload повторно встановлює правила. Створюйте правила за допомогою firewall-cmd, щоб вони відновлювалися після reload.
Два firewall-менеджери на одному сервері. Встановлення ufw або iptables-services разом із firewalld дає два інструменти, які записують правила незалежно один від одного. Результат залежить від того, який сервіс запустився останнім. Оберіть один інструмент. У Rocky і AlmaLinux саме firewalld має підтримку дистрибутива.
Firewall провайдера перед сервером. Багато VPS-панелей мають окремий network firewall. Якщо --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 записує зміни у файл, але не змінює активний firewall. Порт залишається закритим, доки sudo firewall-cmd --reload не завантажить збережену конфігурацію до ядра. Порівняйте sudo firewall-cmd --list-services і sudo firewall-cmd --permanent --list-services: якщо у збереженому списку є запис, якого немає в активному списку, вам потрібно виконати reload.
Використовувати --add-service чи --add-port?
Використовуйте --add-service, якщо для потрібного сервісу існує відповідна назва. Це явно вказує призначення, а sudo firewall-cmd --info-service=https показує, які саме порти охоплює ця назва. Використовуйте --add-port, якщо для вашого сервісу немає визначення або він прослуховує нестандартний порт. Сервіс ssh означає лише 22/tcp, тому для SSH, перенесеного на 2222, потрібні --add-port=2222/tcp і SELinux label для цього порту.
Чому мій Docker container доступний, хоча firewalld показує, що порт закритий?
Опублікований порт переписується власними правилами NAT Docker і перенаправляється до container, тому пакет не доставляється на host. Списки сервісів і портів zone охоплюють лише пакети, доставлені на host. Container відповідає із інтернету, хоча --list-all не показує нічого. Опублікуйте порт лише на loopback за допомогою docker run -d -p 127.0.0.1:8080:80 nginx і розмістіть перед ним reverse proxy.
Чи можна встановити ufw на Rocky Linux замість firewalld?
Два firewall manager на одному сервері записують правила, не знаючи один про одного. Який набір правил залишиться активним, залежить від того, який сервіс запустився останнім. firewalld є підтримуваним інструментом у Rocky Linux і AlmaLinux, уже встановлений у системі та використовує той самий backend nftables, що й ufw. Достатньо один раз розібратися з default zone і прапором --permanent — і ви знатимете весь інструмент.