SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor

Як змінити SSH-порт у SELinux і firewalld

Зміна порту sshd у Rocky Linux, AlmaLinux, CentOS Stream або Fedora: відкрийте firewalld, додайте мітку SELinux і змініть sshd_config без втрати сесії.

Чому зміна SSH-порту тут потребує трьох кроків

Щоб змінити SSH-порт у Rocky Linux, AlmaLinux, CentOS Stream або Fedora, недостатньо відредагувати один файл. Три окремі системи визначають, чи працюватиме підключення через новий порт. firewalld вирішує, чи дійде пакет до машини. SELinux вирішує, чи дозволено sshd взагалі прив’язати цей номер порту. sshd_config визначає, який порт запитує daemon. Якщо пропустити крок із SELinux, daemon відмовиться запускатися. Якщо пропустити крок із firewalld, він запуститься і слухатиме порт, але підключитися до нього буде неможливо.

В Ubuntu це саме завдання потребує одного редагування та перезапуску, оскільки Ubuntu використовує AppArmor замість SELinux і не містить профілю, який обмежує порти, до яких може прив’язуватися sshd. Якщо там працює ufw, потрібно додати одне правило. У цьому полягає вся різниця. У сімействі RHEL після свіжого встановлення firewalld запущений, а SELinux працює в режимі enforcing. Обидві системи враховують номери портів.

Виконайте дії в такому порядку, щоб поточна сесія залишалася активною на кожному кроці:

  1. Відкрийте новий порт у firewalld, поки що залишивши порт 22 відкритим.
  2. Додайте мітку SELinux для нового порту за допомогою semanage.
  3. Вкажіть порт у конфігурації sshd.
  4. Перезапустіть sshd, потім увійдіть через новий порт із другого термінала, перш ніж закривати перший.
Знайдіть вебконсоль свого провайдера (VNC або serial) до початку роботи та перевірте, що можете ввійти через неї. Ця консоль дасть змогу відновити доступ, якщо зміна спричинить проблему. Зміна порту — одна з найпоширеніших причин, через яку користувач втрачає доступ до сервера, за який він щойно заплатив.

Спочатку встановіть semanage

semanage — це інструмент для редагування параметрів політики SELinux. Мінімальна інсталяція Rocky Linux або AlmaLinux не містить цього інструмента. Він входить до пакета policycoreutils-python-utils.

sudo dnf install -y policycoreutils-python-utils

Якщо виконати команду до встановлення цього пакета, буде показано sudo: semanage: command not found. На цьому етапі багато читачів вирішують, що SELinux не встановлено, і пропускають цей крок. SELinux встановлено. Відсутній лише інструмент керування. Якщо синтаксис dnf для вас новий, у еквівалентах команд dnf і apt наведено відповідність до відомих вам команд.

Виберіть порт і перевірте, чи його вже не використовує інший процес

Підійде будь-який вільний TCP-порт від 1024 до 65535. Перед вибором порту виконайте дві перевірки:

sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222

Перша перевірка показує, чи вже прослуховує процес цей порт. Друга показує, чи політика SELinux уже не призначила його іншому типу сервісу. Для вільного порту обидві команди не повертають результатів. Якщо політика вже використовує цей порт, semanage port -a на кроці 2 завершиться помилкою ValueError: Port tcp/2222 already defined. У такому разі виберіть інший номер.

У цьому посібнику як приклад використовується порт 2222. Після 22 це також перший порт, який перевіряє сканер, тому на реальному сервері виберіть менш очевидний номер.

Крок 1: відкрийте порт у firewalld

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

--permanent записує правило у файл зони на диску та не змінює поточну конфігурацію брандмауера. --reload завантажує конфігурацію з диска до поточної конфігурації брандмауера. Якщо пропустити перезавантаження, правило буде створене, але не діятиме до наступного перезапуску firewalld. Це одна з найпоширеніших причин, через які вся процедура нібито безпідставно не працює.

Поки що не змінюйте запис служби ssh. Саме цей запис залишає порт 22 відкритим. Він буде резервним варіантом під час перевірки.

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

Крок 2: призначте порту мітку для SELinux

sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t

-a додає нове призначення порту. -t ssh_port_t — це тип, який використовують порти SSH. Друга команда показує все, що тепер охоплює ssh_port_t, тому перед зміною daemon можна перевірити, що потрібний номер додано.

Чому SELinux взагалі блокує порт

SELinux (security-enhanced Linux) призначає кожному об’єкту в системі мітку, а номери TCP-портів є такими самими об’єктами. Демон SSH працює в обмеженому домені з назвою sshd_t. Політика дозволяє sshd_t прив’язувати TCP-порти з міткою ssh_port_t, а з коробки єдиним портом із такою міткою є 22. Якщо попросити демон прив’язати порт 2222, ядро перевіряє мітку, визначає загальний тип, призначений політикою цьому номеру, і відхиляє дозвіл name_bind для сокета.

Тому ця помилка не схожа на проблему з firewall. Ядро відхиляє операцію ще до створення сокета, що прослуховує порт, тому sshd повідомляє про помилку й завершує роботу. Проблема з firewall має протилежний вигляд: демон працює нормально, а пакети відкидаються під час входження.

getenforce показує, у якому режимі працює система. У режимі Permissive відмову записано в журнал, але її не застосовано, тому зміна порту спочатку працює, а потім перестає працювати, коли хтось виконує setenforce 1 або система перезавантажується в режимі enforcing. У будь-якому разі призначте порту правильну мітку. Посібник з основ SELinux для сервера докладно пояснює режими, контексти та булеві параметри.

Крок 3: задайте порт у конфігурації sshd

У Rocky Linux 9 і 10, AlmaLinux 9 і 10 та актуальних версіях Fedora файл /etc/ssh/sshd_config починається з директиви include, тому найзручніше внести зміну в drop-in-файл. Після цього оновлення пакетів не конфліктуватимуть із вашими змінами.

grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -t

Якщо grep не знаходить рядок Include, як у Rocky Linux 8 та інших старіших образах, додайте Port 2222 безпосередньо у /etc/ssh/sshd_config. sshd -t аналізує всю конфігурацію, включно з drop-in-файлами, і повідомляє про синтаксичні помилки. Виправте всі виявлені помилки до перезапуску, оскільки конфігурація, яку не вдається обробити, призводить до того, що daemon не запускається знову.

Port може зустрічатися більше одного разу, і sshd прослуховує кожен указаний порт. Залишити Port 22 разом із Port 2222 на перший день — простий спосіб підстрахуватися, але не забудьте потім видалити його.

Чи запускається ваш sshd через socket unit?

Деякі образи запускають SSH через socket activation systemd, а не як довготривалий сервіс. У такій конфігурації systemd керує listening socket і передає з’єднання sshd, тому рядок Port у sshd_config повністю ігнорується. Перевірте це, перш ніж щось перезапускати:

systemctl is-enabled sshd.socket

Відповідь enabled означає, що порт задано в socket unit, а не у sshd_config:

sudo systemctl edit sshd.socket
[Socket]
ListenStream=
ListenStream=2222

Порожнє ListenStream= є обов’язковим. Значення накопичуються у drop-in-конфігураціях, тому без порожнього присвоєння, яке спочатку очищає список, socket і надалі слухатиме 22, а також 2222. Застосуйте зміни за допомогою sudo systemctl daemon-reload, а потім виконайте sudo systemctl restart sshd.socket. Якщо unit вимкнений або відсутній на вашому сервері, цей розділ вам не потрібен.

Крок 4: перезапустіть службу, потім перевірте підключення з другого термінала

sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshd

Не закривайте цей термінал. Не виходьте з нього. Відкрийте другий термінал на власному комп’ютері та підключіться через новий порт:

ssh -p 2222 youruser@203.0.113.10

Закривайте першу сесію лише після успішного входу з другого термінала. Якщо підключення не працює, у вас усе ще є shell, з якого можна скасувати всі зміни. Ця проста звичка визначає, чи займе зміна 5 хвилин, чи доведеться витратити весь день у консолі провайдера.

Блокування брандмауером чи заборона SELinux? Як їх розрізнити

З вашого ноутбука ці дві помилки виглядають майже однаково. На сервері вони не схожі одна на одну.

  • Якщо systemctl status sshd показує, що unit завершився з помилкою, демон не отримав свій сокет. Причиною є помилка конфігурації або заборона SELinux.
  • Якщо unit активний, а ss -tlnp показує, що sshd прослуховує новий порт, з демоном усе гаразд. Проблема в мережевому шляху: firewalld, окремий брандмауер провайдера або адреса й порт, до яких ви підключаєтеся.

У випадку SELinux прочитайте запис аудиту, а не вгадуйте:

sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pager

Заборона name_bind для класу tcp_socket містить процес у comm="sshd", номер порту в src= і мітку, яку фактично має порт, у tcontext=. Останнє поле і є відповіддю. Будь-яке значення, крім ssh_port_t, означає, що крок 2 не застосувався до порту, який ви використовуєте. Зазвичай це помилка в номері або неправильний протокол. Встановіть setroubleshoot-server, якщо хочете, щоб sealert перетворив запис на зрозуміле речення.

Повідомлення, яке сам sshd записує, коли ядро відхиляє прив’язування, виглядає так:

error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.

Permission denied на порту вище 1024, для прив’язування до якого не потрібні привілеї root, є ознакою SELinux. Address already in use у тому самому рядку вказує на іншу проблему: порт уже зайнятий іншим процесом. На стороні клієнта різниця між відхиленням з’єднання та перевищенням часу очікування допомагає розрізнити два мережеві випадки: відхилення означає, що пакет дійшов до хоста й жоден процес не прослуховував порт, а перевищення часу очікування означає, що відповіді не було взагалі.

Закрийте порт 22 і оновіть клієнти

Після того як кілька входів через новий порт успішно відпрацюють, закрийте порт 22:

sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

Не змінюйте мітку SELinux для порту 22. Вона надходить із базової політики й нічого не дозволяє, коли firewall перестає пропускати вхідні пакети.

Після цього виправте конфігурацію клієнтів, оскільки кожному інструменту, який використовував порт за замовчуванням, тепер потрібно явно вказати новий порт. Один раз додайте його у ~/.ssh/config на власній машині замість того, щоб постійно вводити -p:

Host myvps
  HostName 203.0.113.10
  Port 2222
  User youruser

scp, sftp, rsync та Ansible також читають цей файл. Завдання резервного копіювання, перевірки моніторингу й скрипти cron, у яких порт 22 прописано безпосередньо, цього не роблять. Знайдіть і виправте їх, поки зміна ще свіжа в пам’яті.

Що дає і чого не дає зміна порту

Вона зменшує шум у журналі. Автоматизовані сканери постійно перевіряють порт 22, тому перенесення служби з цього порту прибирає більшість таких записів із журналу й полегшує пошук реальних подій. Це не засіб захисту. Будь-який сканер, який перевіряє весь діапазон портів, знайде ваш daemon і все одно прочитає його банер версії. Розглядайте зміну порту як адміністративне впорядкування, а основний захист забезпечте автентифікацією лише за ключами та вимкненням входу за паролем. Покрокові інструкції наведено в посібнику із захисту SSH для VPS.

Усе описане вище однаково працює в обох основних RHEL rebuilds, оскільки вони зібрані з однакових джерел. Якщо ви ще обираєте між ними, див. порівняння Rocky Linux і AlmaLinux. Перед виконанням старішого посібника перевірте, який саме release вам надали, за допомогою cat /etc/os-release. Посібники, написані для Rocky Linux 8, досі мають високі позиції в пошуку, а їхні кроки semanage і firewall-cmd залишаються правильними. Однак у Rocky 8 немає рядка include sshd_config.d і socket unit, який потрібно було б враховувати, тому частина цих посібників про sshd не відповідає поточній системі.

fail2ban потрібно повідомити про новий порт

fail2ban немає в базових репозиторіях. Він постачається через EPEL (додаткові пакети для Enterprise Linux):

sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld

Підпакет fail2ban-firewalld змушує fail2ban додавати блокування через firewalld. Це потрібно на сервері, де firewalld керує набором правил.

Стандартний jail sshd задає port = ssh, а це ім’я через /etc/services перетворюється на 22. Після зміни jail стежить за портом, на який ніхто не атакує. Тому він нікого не блокує, хоча невдалі входи накопичуються на 2222. Укажіть номер порту в /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600

backend = systemd читає невдалі спроби з journal, а не з /var/log/secure. Це безпечніший варіант для мінімальної інсталяції, де rsyslog може бути відсутній. Запустіть його за допомогою sudo systemctl enable --now fail2ban і перевірте jail командою sudo fail2ban-client status sshd. Синтаксис jail такий самий, як у налаштуванні fail2ban для SSH в Ubuntu 24.04. Відрізняються лише джерело пакета та дія блокування.

Патчі важливіші за номер порту

Сервер із перенесеним портом SSH і чотирма місяцями невстановлених оновлень безпеки перебуває в гіршому стані, ніж сервер на порту 22, який щоночі автоматично встановлює патчі. Увімкніть автоматичні оновлення в тому самому сеансі, поки ви вже маєте права root: автоматичні оновлення dnf у Rocky Linux та AlmaLinux описує налаштування таймера та вибір між завантаженням оновлень і їхнім встановленням.

FAQ

Чому sshd не запускається після зміни порту в Rocky Linux?

Майже завжди причина полягає у відсутній мітці порту SELinux. sshd працює в обмеженому домені sshd_t, а політика дозволяє йому прив’язуватися лише до портів із міткою ssh_port_t. За замовчуванням це лише порт 22. Ядро відхиляє прив’язування, тому демон завершує роботу замість того, щоб почати прослуховувати порт, а journalctl -u sshd містить рядок такого формату: error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. Виконайте sudo semanage port -a -t ssh_port_t -p tcp 2222, указавши власний номер порту, а потім перезапустіть службу. Якщо semanage не знайдено, спочатку встановіть policycoreutils-python-utils.

Чи потрібен semanage, якщо SELinux працює в permissive mode?

Так. У permissive mode відмова записується в журнал, а прив’язування все одно дозволяється, тому здається, що зміна спрацювала. Але мітка все ще відсутня. Щойно хтось виконає setenforce 1 або система завантажиться з SELINUX=enforcing у /etc/selinux/config, sshd перестане запускатися на цьому порту. Додавання мітки потребує однієї команди й усуває проблему, яка інакше могла б виникнути через кілька тижнів без очевидної причини.

Порт має мітку, sshd працює, то чому підключення завершується тайм-аутом?

Працюючий демон означає, що SELinux не блокує операцію, тому пакет відкидається десь на шляху до сервера. Перевірте sudo firewall-cmd --list-ports для свого порту та переконайтеся, що виконали firewall-cmd --reload після правила --permanent, оскільки саме по собі постійне правило не застосовується до запущеного firewall. Потім перевірте панель керування хостинг-провайдера на наявність окремого мережевого firewall перед VPS. Це друге місце, де часто блокується трафік, і всередині операційної системи цього не буде видно.

Який порт слід використовувати замість 22?

Будь-який вільний TCP-порт від 1024 до 65535. На реальному сервері уникайте 2222 і 22222, оскільки сканери перевіряють їх одразу після 22. Переконайтеся, що номер вільний, за допомогою sudo ss -tlnp, перевірте, що політика SELinux ще не використовує його, за допомогою sudo semanage port -l, і не вибирайте порт, призначений службі, яку ви можете встановити пізніше. Великий номер, який важко запам’ятати, цілком підходить, оскільки ви один раз запишете його у ~/.ssh/config і більше не вводитимете вручну.