Ви змінили порт SSH. Це здавалося відповідальним кроком. Потім термінал завис при підключенні, моніторинг запалився, і ви зрозуміли, що, можливо, щойно
навчили сервер ігнорувати вас. Найгірше: з середини все виглядає «ніби як нормально».
Випадок №87 — класика: sshd налаштовано на новий порт, але фаєрвол та порядок завантаження не погоджуються. Або sshd ніколи не прив’язав сокет, який ви собі уявляли.
Виправлення — не «перезапустити і помолитися». Це контрольована міграція з перевірками та планом відкату, що витримає затримки, людські помилки і systemd.
Що реально змінилося (і що ні)
Зміна порту SSH — це дві окремі проблеми, які люди люблять зливати в одну:
- sshd має слухати на новому порту (і не провалювати перевірку конфігурації, не прив’язуватися до неправильного інтерфейсу або не блокуватися іншим сервісом).
- мережа має дозволяти новий порт (локальні правила фаєрволу, групи безпеки у хмарі, верхньорівневі ACL, джамп-хости, NAT та будь-яке «корпоративне» обладнання на краю мережі).
Debian 13 не «магічно» блокує ваш новий порт, але він поставляється з сучасними налаштуваннями за замовчуванням: socket-активація systemd у деяких конфігураціях, nftables як
бекап-фаєрвол для багатьох інструментів адміністрування та дедалі більш жорсткі політики хардінгу. Порядок запуску сервісів при завантаженні може мати більше значення, ніж
вам би хотілося, особливо якщо правила фаєрволу застосовуються пізніше, несподівано очищуються або замінюються інструментом, який «думає», що він єдиний власник.
Ось основна правда: якщо ви не можете довести, що саме слухає і що саме дозволено, ви робите припущення. Припущення призводять до заявок, що починаються з «Вчора працювало» і
закінчуються «ми підключили rescue ISO».
Цікаві факти та коротка історія (те, що змінює підхід до налагодження)
- Порт 22 не завжди був стандартом. На ранніх розгортаннях SSH порти були більш гнучкими; конвенції з’явилися з розвитком інструментів і документації.
- Зміна порту не «зашифровує» SSH у криптографічному сенсі. Це здебільшого зменшує шум від масових сканів. Операційно це може бути корисно, але не замінює реальних заходів безпеки.
- systemd зробив запуск сервісів детермінованим… і водночас легше випадково порушити порядок запуску. Якщо додавати drop-in без обережності, можна створити змагання при завантаженні, що проявляються лише після перезавантаження.
- nftables замінив iptables як напрямок розвитку Linux-фаєрволів. Багато систем досі мають сумісні шари iptables; змішання інструментів може створити ситуації «правила виглядають правильно, але неактивні».
- OpenSSH давно підтримує кілька портів для прослуховування. Можна одночасно слухати 22 і 2222 під час вікна міграції, а потім видалити старий порт пізніше.
- Хмарні фаєрволи відокремлені від хостових фаєрволів. Ви можете відкрити nftables, але бути заблокованим групою безпеки, або навпаки.
- sshd може мовчки відмовлятися від роботи з погляду віддалених клієнтів. Погана конфігурація може не дозволити прив’язку; сервіс може зациклюватися на перезапусках, а клієнти бачитимуть «Connection refused» або таймаути.
- У деяких середовищах використовують socket-активацію systemd для ssh. У такому випадку «слухаючий порт» контролюється сокет-юнітом, не лише sshd_config.
Одну цитату я тримаю на видноті, бо вона описує сутність роботи в реченні:
«Надія — не стратегія.»
— Джин Кранц
Швидкий план діагностики
Коли SSH ламається після зміни порту, вам не потрібна філософія. Вам потрібна послідовність дій, яка швидко знаходить вузьке місце.
Перш за все: визначте, який саме збій ви бачите
- «Connection refused»: на IP:порт ніщо не слухає, або фаєрвол активно відхиляє з’єднання.
- Таймаут / зависання: фаєрвол відкидає пакети, неправильна маршрутизація/NAT або ви звертаєтеся не за тим IP.
- Рукостискання, але автентифікація не проходить: sshd доступний, але змінено налаштування автентифікації (користувачі/ключі/AllowUsers/Match-блоки).
По-друге: доведіть, що sshd слухає там, де ви думаєте
- Перевірте
ss -lntpлокально. - Перевірте
systemctl status sshта логи. - Якщо задіяна socket-активація, перевірте
systemctl status ssh.socket.
По-третє: доведіть, що порт дозволений енд-ту-енд
- Фаєрвол хоста: стан nftables/UFW/iptables.
- Верхній фаєрвол: група безпеки хмари, NACL, корпоративний ACL або маршрутизатор.
- З віддаленого хоста:
nc -vzабоssh -vvv, щоб побачити, чи повертаються SYN.
По-четверте: підтвердіть порядок завантаження, якщо проблема лише після перезавантаження
- Шукайте сервіси фаєрволу, що очищують/повторно застосовують правила після старту sshd.
- Перевірте залежності: sshd не повинен «успішно» стартувати, а потім втратити порт через те, що правила були замінені.
Жарт №1: Змінювати порти SSH о 16:59 — чудовий спосіб гарантувати, що ви будете «на зв’язку» весь вікенд.
Як змінювати порти SSH без самопороджених відключень
Найбезпечніша зміна порту — це міграція, а не перемикання. Тимчасово тримайте обидва порти, перевірте з принаймні двох незалежних мереж-клієнтів, а потім приберіть старий порт.
Так, це нудно. Так, нудне — це мета.
Принцип 1: Зберігайте страховку
Перед тим як щось змінити: переконайтеся, що у вас є шлях поза основним каналом доступу. Це може бути послідовна консоль хмари, IPMI/iDRAC/iLO, консоль гіпервізора
або резервний «break glass» бастіон. Якщо його немає — ваше вікно змін вже є ризиком.
Принцип 2: Перевіряйте конфігурацію перед перезапуском
sshd суворий не просто так. Помилка в sshd_config може впасти сервіс. Перевіряйте конфіг sshd -t і лише потім перезавантажуйте.
Reload кращий за restart, коли ви підключені віддалено — restart закриває існуючі сесії швидше.
Принцип 3: Не покладайтеся на один інструмент фаєрволу
Виберіть один авторитет: nftables або UFW (який керує nftables/iptables під капотом), або політику CM, що володіє правилами.
Змішування команд iptables у системі, якою керує nftables, породжує правила, що виглядають, але не застосовуються, або застосовуються до наступного перезапуску.
Принцип 4: Доведіть доступність ззовні
Локальні перевірки обманюють через упущення. Сервер може слухати, але група безпеки блокує порт. Перевіряйте з іншого хоста в Інтернеті
або принаймні з іншого сегмента мережі, ніж ваш адміністраторський робочий стіл.
Принцип 5: Зробіть можливим відкат за 60 секунд
Коли редагуєте порт, підготуйте відкат: тримайте відкриту root-оболонку, заплануйте автоматичний відкат фаєрволу через at або systemd-run,
і скасовуйте його лише після підтвердження підключення по новому порту.
Жарт №2: Фаєрволи схожі на корпоративні оргструктури — кожен думає, що розуміє їх, поки не знадобиться зробити маленьку виняткову операцію.
Практичні завдання (команди, виводи, рішення)
Це ті завдання, які я реально виконую в продакшені, коли хтось каже «SSH помер після зміни порту». Кожне містить, що означає вивід і як приймати рішення. Виконуйте їх у порядку, коли можливо.
Завдання 1: Підтвердити, який порт sshd вважає за потрібне
cr0x@server:~$ sudo sshd -T | grep -E '^(port|listenaddress)\b'
port 2222
listenaddress 0.0.0.0
listenaddress ::
Значення: Це ефективна конфігурація sshd після включених файлів і Match-блоків. Якщо port все ще показує 22, ваша зміна не застосувалася або її переоприділено.
Якщо listenaddress обмежений, ви можете прив’язуватися тільки до інтерфейсу управління.
Рішення: Якщо порт неправильний — виправте конфігурацію в першу чергу. Якщо порт правильний — переходьте до перевірки прослуховування сокетів.
Завдання 2: Перевірити синтаксис конфігу sshd перед перезавантаженням
cr0x@server:~$ sudo sshd -t
cr0x@server:~$ echo $?
0
Значення: Код виходу 0 означає, що синтаксис ОК. Невід’ємне значення означає, що sshd не запуститься з цією конфігурацією.
Рішення: Якщо код відмінний від нуля — не перезапускайте. Виправте конфіг і знову запустіть sshd -t.
Завдання 3: Перевірити, що реально слухає на машині
cr0x@server:~$ sudo ss -lntp | grep -E '(:22|:2222)\b' || true
LISTEN 0 128 0.0.0.0:2222 0.0.0.0:* users:(("sshd",pid=944,fd=3))
LISTEN 0 128 [::]:2222 [::]:* users:(("sshd",pid=944,fd=4))
Значення: sshd прив’язано на IPv4 і IPv6 для порту 2222. Якщо ви бачите тільки IPv6 — клієнти IPv4 зазнають невдачі.
Якщо нічого не видно — sshd не прив’язався: або він зупинений, або працює socket-активація, або він аварійно завершився.
Рішення: Якщо не слухає — перевірте стан systemd і логи далі.
Завдання 4: Перевірити стан сервісу sshd і останні помилки
cr0x@server:~$ systemctl status ssh --no-pager
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; preset: enabled)
Active: active (running) since Wed 2025-12-31 10:11:22 UTC; 2min 9s ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 944 (sshd)
Tasks: 1 (limit: 19000)
Memory: 6.4M
CPU: 72ms
CGroup: /system.slice/ssh.service
└─944 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
Значення: Статус running — добре, але не означає, що доступний ззовні. Якщо ви бачите циклічні перезапуски — ймовірно проблеми з конфігурацією або прив’язкою.
Рішення: Якщо активний — переходьте до перевірки фаєрволу. Якщо падає — загляньте в логи.
Завдання 5: Прочитати логи sshd щодо проблем прив’язки і автентифікації
cr0x@server:~$ sudo journalctl -u ssh -n 50 --no-pager
Dec 31 10:11:21 server sshd[944]: Server listening on 0.0.0.0 port 2222.
Dec 31 10:11:21 server sshd[944]: Server listening on :: port 2222.
Значення: Прив’язка пройшла успішно. Якщо замість цього ви бачите «Bad configuration option» або «Could not load host key», sshd може не приймати з’єднання.
Рішення: Якщо прив’язка ОК — рухайтеся далі: фаєрвол і зовнішні шари.
Завдання 6: Виявити, чи задіяна socket-активація systemd
cr0x@server:~$ systemctl list-unit-files | grep -E '^ssh\.socket'
ssh.socket disabled enabled
Значення: Якщо ssh.socket enabled і active, воно може визначати порт(и) для прослуховування. Якщо disabled — sshd прив’язується прямо.
Рішення: Якщо увімкнено socket-активацію — перевірте та редагуйте юніт сокета, а не лише sshd_config.
Завдання 7: Інспектувати юніт сокета щодо портів прослуховування (якщо застосовно)
cr0x@server:~$ systemctl cat ssh.socket
# /lib/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target
[Socket]
ListenStream=22
Accept=no
[Install]
WantedBy=sockets.target
Значення: Цей сокет все ще на 22. Якщо він активний — клієнти, що потрапляють на 2222, зазнають невдачі.
Рішення: Оновіть ListenStream (або додайте ще один) і перезапустіть сокет, або вимкніть socket-активацію й запустіть ssh.service звично.
Завдання 8: Підтвердити бекенд фаєрволу і активний набір правил
cr0x@server:~$ sudo update-alternatives --display iptables | sed -n '1,12p'
iptables - auto mode
link best version is /usr/sbin/iptables-nft
link currently points to /usr/sbin/iptables-nft
link iptables is /usr/sbin/iptables
slave iptables-restore is /usr/sbin/iptables-restore
slave iptables-save is /usr/sbin/iptables-save
Значення: Цей хост використовує iptables-nft у режимі сумісності. Якщо ви виконуєте «класичні» команди iptables, сподіваючись на legacy-поведінку, ваша модель може відрізнятися від реальності.
Рішення: Краще інспектувати nftables напряму за допомогою nft list ruleset.
Завдання 9: Вивести правила nftables і знайти ваш порт SSH
cr0x@server:~$ sudo nft list ruleset | sed -n '1,120p'
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif "lo" accept
tcp dport 2222 accept
icmp type echo-request accept
}
}
Значення: Політика drop означає «усе, що явно не дозволено — вмирає». У вас є правило allow для tcp/2222.
Рішення: Якщо правила немає — додайте її перед тим, як переводити sshd на новий порт (або тимчасово тримайте обидва порти).
Завдання 10: Якщо використовуєте UFW — перевірте, що він дійсно дозволяє новий порт
cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
2222/tcp ALLOW IN Anywhere
2222/tcp (v6) ALLOW IN Anywhere (v6)
Значення: UFW дозволяє tcp/2222 для IPv4 і IPv6.
Рішення: Додайте обидві сімейства адрес, якщо ви використовуєте dual-stack. Потім тестуйте зовні.
Завдання 11: Тест з самого сервера (саніті-чек, але не доказ)
cr0x@server:~$ nc -vz 127.0.0.1 2222
Connection to 127.0.0.1 2222 port [tcp/*] succeeded!
Значення: Підключення по локалхосту працює. Це доводить «слухає», але не «доступно ззовні».
Рішення: Якщо це падає — sshd не слухає або локальна політика блокує. Виправляйте локально перед перевіркою зовнішніх шарів.
Завдання 12: Тест з віддаленого хоста з verbose SSH
cr0x@server:~$ ssh -vvv -p 2222 admin@203.0.113.10
OpenSSH_9.7p1 Debian-2, OpenSSL 3.0.14 4 Jun 2024
debug1: Connecting to 203.0.113.10 [203.0.113.10] port 2222.
debug1: Connection established.
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.7p1 Debian-2
debug1: Authenticating to 203.0.113.10:2222 as 'admin'
debug1: Offering public key: /home/cr0x/.ssh/id_ed25519
debug1: Server accepts key: /home/cr0x/.ssh/id_ed25519
Authenticated to 203.0.113.10 ([203.0.113.10]:2222).
Значення: Це показує критичні етапи: TCP connect, handshake, автентифікація. Якщо воно зависає до «Connection established» — ймовірно фаєрвол/маршрутизація.
Якщо handshake відбувся, але автентифікація не пройшла — зосередьтеся на налаштуванняхssh автентифікації.
Рішення: Якщо віддалене підключення працює — тримайте сесію відкритою і переходьте до видалення старого порту пізніше. Якщо ні — ще не видаляйте 22.
Завдання 13: Підтвердити, що сервіс доступний на публічному інтерфейсі (помилки з listenaddress)
cr0x@server:~$ ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
ens3 UP 203.0.113.10/24 2001:db8:10::10/64
Значення: Якщо sshd прив’язаний до 127.0.0.1 або до приватного інтерфейсу — віддалений доступ не працюватиме.
Рішення: Переконайтеся, що ListenAddress в sshd_config охоплює потрібні інтерфейси, або видаліть його, щоб прив’язатися до всіх.
Завдання 14: Виявити баги «працює до перезавантаження» через порядок завантаження
cr0x@server:~$ systemd-analyze critical-chain ssh.service
ssh.service +42ms
└─network-online.target @3.211s
└─systemd-networkd-wait-online.service @1.902s +1.292s
└─systemd-networkd.service @1.501s +386ms
└─systemd-udevd.service @1.221s +265ms
└─systemd-tmpfiles-setup-dev.service @1.159s +54ms
└─kmod-static-nodes.service @1.085s +58ms
└─systemd-journald.socket @1.010s
Значення: Це показує, за що ssh чекав. Якщо ваш сервіс фаєрволу стартує пізніше і очищує правила, ssh може бути доступним коротко, а потім ні.
Рішення: Перевірте порядок юнітів фаєрволу і забезпечте, щоб фаєрвол застосовувався до того, як ви покладаєтеся на нього для доступу, або щоб фаєрвол не очищував встановлені політики несподівано.
Завдання 15: Перевірити порядок сервісу фаєрволу і чи очищує він правила
cr0x@server:~$ systemctl status nftables --no-pager
● nftables.service - nftables
Loaded: loaded (/lib/systemd/system/nftables.service; enabled; preset: enabled)
Active: active (exited) since Wed 2025-12-31 10:10:59 UTC; 2min 50s ago
Docs: man:nft(8)
Process: 611 ExecStart=/usr/sbin/nft -f /etc/nftables.conf (code=exited, status=0/SUCCESS)
Значення: nftables був завантажений з файлу і вийшов (нормально). Якщо у вас інший менеджер фаєрволу — перевірте його юніт і скрипти на наявність «flush rules».
Рішення: Якщо фаєрвол не увімкнено — правила можуть не зберігатися після перезавантаження. Увімкніть його або керуйте постійністю іншим способом.
Завдання 16: Довести стійкість: перевірка конфігу, який витримає перезавантаження без реального перезапуску
cr0x@server:~$ sudo nft -c -f /etc/nftables.conf && echo "nftables.conf parses OK"
nftables.conf parses OK
Значення: -c перевіряє синтаксис і семантику без застосування. Якщо це не проходить — перезавантаження може застосувати пошкоджений ruleset і заблокувати SSH.
Рішення: Виправте помилки парсингу зараз. Потім підтвердіть, що юніт увімкнено, щоб він завантажив правильні правила при завантаженні.
Завдання 17: Запланувати тимчасовий відкат змін фаєрволу
cr0x@server:~$ echo "sudo nft flush ruleset; sudo nft -f /root/nftables.known-good.conf" | at now + 5 minutes
warning: commands will be executed using /bin/sh
job 12 at Wed Dec 31 10:20:00 2025
Значення: Ви щойно створили страхувальний парашут. Якщо ви заблокуєте себе, сервер поверне назад через 5 хвилин (за умови, що job зможе виконатися).
Рішення: Скасовуйте job лише після підтвердження віддаленого SSH на новому порту і перевірки, що правила фаєрволу зберігаються.
Завдання 18: Скасувати відкат, коли новий порт підтверджено
cr0x@server:~$ atq
12 Wed Dec 31 10:20:00 2025 a root
cr0x@server:~$ atrm 12
cr0x@server:~$ atq
Значення: Ніяких відкатів у черзі не лишається.
Рішення: Тепер безпечно прибирати Port 22 пізніше, бо ви довели доступ і прибрали тренувальні колеса.
Порядок systemd: sshd проти фаєрволу під час завантаження
Більшість випадків «я змінив порт і все працювало до перезавантаження» — не містичні. Це проблеми порядку і власності:
фаєрвол завантажується після sshd і замінює правила, інструмент очищує ruleset, або агент керування конфігурацією записує стару політику під час завантаження.
Що означає «порядок» у цьому контексті
Порядок systemd — це не тільки те, який юніт стартує першим. Це також те, який юніт вважається «готовим» і що він тягне через залежності.
sshd статус «active (running)» не означає «доступний з вашого ноутбука». Це лише означає, що демон живий.
Забезпечити застосування правил фаєрволу рано, послідовно і з одного джерела
На Debian, якщо ви керуєте фаєрволом через nftables.service, правила зазвичай завантажуються з /etc/nftables.conf.
Якщо ви керуєте через UFW — UFW має власний systemd-сервіс і згенерує правила.
Якщо ви керуєте через корпоративний агент — він може перезаписувати обидва.
Мета проста:
- Політика фаєрволу застосовується до того, як ви на неї покладаєтесь для доступу.
- Політика фаєрволу не очищується і не замінюється несподівано після того, як sshd вже працює.
- Потрібний вам порт SSH дозволено у тій же політиці, що і фактично завантажується при завантаженні.
Практичний підхід: тримайте sshd доступним під час переходів
Під час міграції портів дозволяйте обидва — старий і новий — у фаєрволі, і налаштуйте sshd тимчасово слухати обидва порти.
Потім видаліть порт 22 з фаєрволу лише після підтвердження нового доступу з кількох місць і після мінімум одного перезавантаження.
Безпечне редагування sshd_config: кілька портів
OpenSSH підтримує кілька директив Port. Для вікна міграції зробіть так:
cr0x@server:~$ sudo sh -c 'printf "\n# Migration window: keep 22 temporarily\nPort 22\nPort 2222\n" >> /etc/ssh/sshd_config'
Потім перевірте і перезавантажте (а не перезапускайте) коли ви віддалено:
cr0x@server:~$ sudo sshd -t && sudo systemctl reload ssh
Рішення: Видаляйте Port 22 тільки після того, як ви зможете підключитися стабільно на новому порту і підтверджено, що правила фаєрволу зберігаються.
Коли ssh.socket змінює правила гри
Якщо ssh.socket увімкнено, systemd володіє слухаючим сокетом. У такому випадку:
- Зміна
Portв sshd_config може не давати очікуваного результату. - Слід змінювати
ListenStreamу сокет-юніті (краще через drop-in). - Після цього перезапустіть саме юніт сокета, а не лише сервіс.
Якщо ви не хочете socket-активацію — вимкніть її свідомо; не живіть у напівстані, коли ви не впевнені, хто володіє портом.
Рецепти для фаєрволу: nftables, UFW, iptables
«Правильний» фаєрвол — це той, яким ваша система реально користується послідовно через перезавантаження і автоматизацію. На Debian 13 nftables — найчистіший шлях.
Якщо ви використовуєте UFW — тримайте його єдиним інтерфейсом. Якщо у вас legacy-інфраструктура з iptables — будьте явними щодо того, чи це legacy або nft-бекенд.
nftables: дозволити новий порт SSH (inet table)
Приклад фрагмента для /etc/nftables.conf. Припускається політика input за замовчуванням drop:
cr0x@server:~$ sudo grep -n 'chain input' -n /etc/nftables.conf | head
12: chain input {
Додайте правило allow поруч з іншими TCP-accept:
cr0x@server:~$ sudo nft add rule inet filter input tcp dport 2222 accept
Значення: Це змінює поточний ruleset, але не обов’язково конфіг-файл. Якщо перезавантажитися без збереження — правило зникне.
Рішення: Негайно відобразіть зміну в /etc/nftables.conf (або у вашому include) і перевірте nft -c.
UFW: дозволити новий порт SSH (і зробити його живучим)
cr0x@server:~$ sudo ufw allow 2222/tcp
Rule added
Rule added (v6)
Значення: UFW створив правила для IPv4 і IPv6.
Рішення: Тримайте ufw status verbose як джерело істини. Не змішуйте з сирими nft-правилами, якщо не хочете налагоджувати о 2:00.
iptables (legacy-інфраструктура): обережно дозволити новий порт
cr0x@server:~$ sudo iptables -S INPUT | sed -n '1,25p'
-P INPUT DROP
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
Додайте нове правило:
cr0x@server:~$ sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
Значення: Правило додано в кінець; якщо порядок важливий (а часто важливий), можливо краще вставити перед правилом reject/log.
Рішення: Забезпечте збереження через ваш механізм (файл конфігурації або сервіс). Інакше перезавантаження скасує зміни.
Не забудьте верхній фаєрвол
Хостовий фаєрвол може бути ідеальним, але марним, якщо:
- група безпеки хмари блокує 2222,
- корпоративний периметрний ACL дозволяє лише 22 для вашої підмережі,
- health check балансувальника закріплений за 22 і оголошує вузол мертвим.
Ваші докази в поведінці мережі: «refused» зазвичай означає, що ви досягли хоста; таймаути зазвичай означають, що не досягли. Ставтеся до цього, як до компаса.
Три корпоративні історії з практики
1) Інцидент через неправильне припущення: «Ми відкрили фаєрвол»
Середня компанія мігрувала флот на Debian 13 і вирішила «зменшити поверхню атаки», перемістивши SSH на 2222. Інженер на виклику відкрив 2222 в UFW
і підтвердив, що ss -lntp показує sshd, що слухає. Зелені галочки. Вони потім прибрали порт 22 скрізь. Впевнено, охайно і помилково.
Наступного ранку половина флоту була недоступна. Не всі — лише хости в одному регіоні. Логи на доступних хостах були чисті, а на недоступних в консолі було видно, що sshd працює.
Команда витратила години, шукаючи фантомні баги sshd і навіть перебудувала одну ВМ з образу, щоб «скинути» її.
Корінь проблеми був зовнішній: шаблон групи безпеки у хмарі був специфічний для регіону. В одному регіоні дозволяли лише 22, в іншому «SSH» як іменована служба мапилася на 22, і лише в третьому була правило для 2222. Припущення інженера — «фаєрвол хоста = доступ» — стало пасткою.
Виправлення було нудним: оновити групи безпеки, організувати слухання на обох портах протягом 48 годин і додати зовнішній тест доступу в процедуру змін.
Команда навчилась розглядати «я можу підключитися зсередини VPC» як часткову істину, не як остаточну перемогу.
2) Оптимізація, що обернулася проти: «Спрощуємо сервіс фаєрволу»
Велика платформа стандартизувала nftables і написала короткий oneshot systemd-юнит, який очищував і перезавантажував ruleset на буті.
Мета була логічною: одне джерело істини, без дрейфу, швидке завантаження. Вони розгорнули це широко і поїхали далі.
Через кілька тижнів інша команда змінила порти SSH під погодженим вікном. Вони оновили /etc/nftables.conf, перезавантажили nftables, перевірили зовнішній доступ
і потім перезавантажили для апдейту ядра. Після перезавантаження SSH був мертвий — але тільки періодично для деяких хостів.
Причина — той самий «оптимізаційний» юніт. Він запускався після network-online, але до остаточного визначення імен інтерфейсів, і при цьому спочатку очищав правила.
Короткий проміжок часу хост мав політику drop без дозволених правил. Деякі з’єднання намагалися у цей проміжок і провалилися.
Люди назвали це «SSH зламався», але насправді це був змаг при завантаженні плюс агресивне очищення.
Постійне виправлення: припинити необдумане очищення, завантажувати атомарний ruleset і розмістити юніт фаєрволу раніше, щоб сервіси, що залежать від вхідного доступу,
не зазнавали короткого «deny all». І ще: не «оптимізуйте» запуск фаєрволу без вимірювань, як він впливає на доступність під час буту.
3) Нудна, але правильна практика, що врятувала день: подвійний порт + таймований відкат
Фінансова команда мала правило: будь-яка зміна, що може заблокувати доступ, повинна мати таймований відкат. Не «ми будемо обережні». Реальний запланований відкат.
Люди скаржилися, що це параноя. Потім одного п’ятничного вечора це спрацювало тихо і без драм.
Інженер поміняв SSH на 2222 і оновив фаєрвол. Він працював з їхньої робочої станції. Не працював з CI-ранерів, які жили в окремій підмережі з власною політикою egress. Ніхто не помітив поки не почалися відмови розгортання.
У команди ще була відкрита SSH-сесія, але вони були на відстані одного розриву від реального інциденту.
Завдяки запланованому відкату вони могли експериментувати безпечніше. Відкрили 22 тимчасово, виправили політику для ранерів, протестували 2222 з обох мереж і лише потім прибрали 22. Жодних rescue-консолей, жодних переінсталяцій, жодних панік щодо паролів від гіпервізора.
Висновок не дивний: найкраща практика надійності часто виглядає як зайва церемонія — допоки вона не рятує від простою.
Типові помилки: симптом → корінь проблеми → виправлення
1) Симптом: «Connection refused» на новому порті
- Корінь: sshd не слухає на цьому порту, або прив’язаний тільки до localhost/іншого інтерфейсу, або ssh.socket все ще на 22.
- Виправлення: Перевірте
sshd -T,ss -lntpіsystemctl cat ssh.socket. ВиправтеPort/ListenAddressабо юніт сокета, перевіртеsshd -tі потім reload.
2) Симптом: Таймаут / зависання при підключенні
- Корінь: фаєрвол відкидає (локальний або зовнішній), неправильний IP, помилка маршрутизації/NAT або група безпеки не оновлена.
- Виправлення: З віддаленого хоста запустіть
ssh -vvv. На сервері перевірте nftables/UFW. Потім підтвердіть правила зверху. Таймаути рідко означають «sshd некоректно налаштовано».
3) Симптом: Працює з однієї мережі, не працює з іншої
- Корінь: асиметричні allowlist-и; корпоративний egress блокує високі порти; оновлено лише один шлях доступу.
- Виправлення: Тестуйте принаймні з двох точок (офіс + CI підмережа або домашній ISP + бастіон). Оновіть ACL. Розгляньте залишити 22 відкритим, але обмеженим до IP-бастіона під час міграції.
4) Симптом: Працює до перезавантаження, потім не працює
- Корінь: правила фаєрволу не зберігаються; сервіс під час буту очищує правила; socket-активація повертає попередній стан; CM перезаписав ваші зміни.
- Виправлення: Переконайтеся, що фаєрвол сервіс увімкнено і завантажує валідний конфіг. Підтвердіть
nft -c -f /etc/nftables.conf. Аудитуйтеsystemctl list-dependenciesдля вашого інструмента фаєрволу і перевірте політики CM.
5) Симптом: SSH підключається, але автентифікація не проходить після зміни порту
- Корінь: Ви змінили не лише порт:
AllowUsers,PasswordAuthentication,PubkeyAuthenticationабоMatch-блок застосовується інакше, ніж очікувалося. - Виправлення: Використайте
sshd -Tдля перегляду ефективних налаштувань; перевіртеjournalctl -u sshдля повідомлень про автентифікацію; переконайтеся, що файли ключів і права доступу правильні.
6) Симптом: IPv6 працює, IPv4 не працює (або навпаки)
- Корінь: sshd прив’язано тільки до однієї сімейства; правила фаєрволу є тільки для v4 або v6; клієнти віддають перевагу сімейству, яке ви не тестували.
- Виправлення: Переконайтеся, що
ssпоказує і0.0.0.0:2222, і[::]:2222, якщо потрібен dual-stack. Віддзеркальте правила для обох сімейств.
7) Симптом: Порт виглядає відкритим локально, але віддалений бачить «No route to host»
- Корінь: проблема маршрутизації/ACL зверху; іноді ICMP блокується і проблеми з MTU ускладнюють діагностику, але «No route» зазвичай мережеве.
- Виправлення: Підтвердіть правильність публічного IP, перевірте групи безпеки/NACL і протестуйте з хоста в тій же регіональній підмережі.
Чеклісти / покроковий план
План A: Безпечна міграція (рекомендовано для продакшену)
- Тримайте існуючу SSH-сесію відкритою (бажано дві: одна root/sudo оболонка, одна у режимі спостереження).
- Підтвердіть наявність поза-канального доступу (консоль хмари, IPMI, консоль гіпервізора).
- Спочатку відкрийте новий порт у фаєрволі (хостовий і верхній фаєрвол). Не видаляйте 22 ще.
- Налаштуйте sshd на прослуховування обох портів:
Port 22іPort 2222. - Перевірте конфіг:
sshd -tіsshd -T | grep '^port '. - Перезавантажте sshd (не restart):
systemctl reload ssh. - Переконайтеся в прослуховуванні сокетів:
ss -lntp | grep ':2222'. - Протестуйте з двох віддалених точок: робоча станція + хост в іншій мережі.
- Заплануйте job відкату перед видаленням 22; скасовуйте його лише після успіху.
- Перезавантажтеся хоча б раз під час вікна, якщо можете, щоб довести стійкість і порядок завантаження.
- Приберіть порт 22 з конфігу sshd і фаєрволу після вікна міграції.
- Оновіть автоматизацію (Ansible інвентар, конфіги бастіона, моніторинг, runbook-и інцидентів).
План B: Екстрене відновлення, якщо ви вже заблоковані
- Використайте поза-канальну консоль для доступу до хоста.
- Перевірте стан sshd і логи:
systemctl status ssh,journalctl -u ssh. - Перевірте прослуховувані порти:
ss -lntp. - Тимчасово дозволіть порт 22 (або відомий робочий порт) в хостовому і верхньому фаєрволі.
- Відкотіть sshd_config до подвійного порту і перевірте
sshd -t. - Reload sshd, потім тестуйте зовні.
- Тільки після цього повторюйте контрольовану міграцію за Планом A.
План C: Якщо увімкнена socket-активація systemd
- Підтвердіть власність: перевірте, чи
ssh.socketувімкнено і активне. - Редагуйте через drop-in, а не змінюйте vendor-юніти напряму.
- Додайте новий ListenStream для міграції (наприклад, 22 і 2222), потім reload daemon і restart socket.
- Перевірте за допомогою
ss -lntpі віддалених тестів. - Пізніше видаліть 22, видаливши старий ListenStream.
FAQ
1) Чи варто змінювати порт SSH?
Це не чарівний засіб безпеки. Це зменшення шуму. Якщо ви вже вимагаєте ключі, вимкнули парольну автентифікацію і обмежили доступ за IP або через бастіон, зміна порту — опціональна.
У середовищах з високим шумом вона може зменшити спам у логах і спроби грубої сили. Розглядайте це як операційне налаштування, а не як основний контроль безпеки.
2) Перезавантажувати чи перезавантажувати (restart vs reload) sshd?
Коли ви підключені віддалено — робіть reload. Reload застосовує конфіг без закриття існуючих сесій у більшості випадків. Restart підходить, коли у вас є консоль або вікно обслуговування,
але це зайвий ризик під час зміни того, через що ви підключені.
3) Чи може sshd слухати на двох портах одночасно?
Так. Додайте кілька рядків Port у /etc/ssh/sshd_config. Це найнадійніша техніка міграції, бо відкатна і тестовна.
4) Я змінив Port, але sshd все ще слухає на 22. Чому?
Типові причини: пізніший файл конфігурації переоприділяє (includes), Match-блок змінює поведінку або socket-активація systemd має ssh.socket все ще на 22.
Використовуйте sshd -T і systemctl cat ssh.socket, щоб припинити гадати.
5) Чому я отримую таймаути замість «refused»?
Таймаути зазвичай означають, що пакети відкидаються: хостовий фаєрвол з політикою drop, група безпеки, верхній ACL або маршрутизація. «Refused» зазвичай означає, що ви досягли хоста
і ніщо не слухає (або воно активно відкидає). Ця відмінність — один із найкращих сигналі для діагностики.
6) Чи потрібно відкривати порт і для IPv6?
Якщо хост має IPv6 з’єднання і клієнти можуть його досягнути — так. Інакше ви отримаєте непослідовні результати: один клієнт хітає v6 і працює, інший хітає v4 і провалюється.
Дзеркальте правила для обох сімейств, якщо у вас dual-stack.
7) Яка найнадійніша техніка відкату?
Тримайте існуючу сесію відкритою і заплануйте таймований відкат фаєрволу та/або конфігу sshd через at або systemd-run.
Скасовуйте відкат лише після успішного підключення на новому порту з зовнішнього хоста і перевірки стійкості після перезавантаження.
8) Як уникнути поломки автоматизації і моніторингу?
Інвентар і інструменти часто припускають порт 22: CM, бекап-агенти, перевірки моніторингу, бастіони і CI ранери.
Оновіть ці конфіги під час вікна міграції, коли працюють обидва порти, а потім прибирайте 22. Якщо ви перемкнули першим — ввечері ви будете шукати кожне приховане припущення.
9) Чи ламає зміна порту fail2ban або правила IDS?
Може. Деякі правила та jail-и прив’язані до «ssh» або до порту 22. Після міграції перевірте, що ваші інструменти безпеки слідкують за новим портом і не стоять осторонь.
10) Чи варто обмежувати SSH за source IP замість зміни порту?
Краще обмеження за source (лише бастіон, VPN або allowlist адміністративних IP). Зміна порту може бути додатковим шаром, але контроль доступу краще за прихованість.
Поєднуйте обидва підходи, якщо це відповідає вашій моделі загроз і операційному толерантності.
Висновок: практичні наступні кроки
Якщо ви візьмете з випадку №87 лише одну річ — нехай це буде ось що: ставтеся до зміни порту SSH як до виробничої міграції, а не до дрібної зміни конфігу. Відкрийте новий шлях спочатку,
тримайте старий під час валідації, доведіть доступність ззовні і лише потім закрийте старе вікно.
Наступні кроки, що швидко дають результат:
- Запустіть
sshd -Tіss -lntp, щоб підтвердити реальність, а не намір. - Виберіть один авторитет фаєрволу (nftables або UFW) і забезпечте стійкість правил через перезавантаження.
- Прийміть практику подвійного порту для міграції плюс таймований відкат як стандартну процедуру.
- Перезавантажте сервіс під час вікна змін хоча б раз, якщо можете, щоб виявити проблеми порядку і стійкості, поки люди ще на зв’язку.
Продакшен-системи не винагороджують сміливість. Вони винагороджують повторювані звички, чисті докази і ту параною, що виглядає як професіоналізм.