Ви вмикаєте VPN, SSH-сеанс зависає, і ваш продуктивний сервер перетворюється на дуже дорогий прес-пап’єт.
Десь між «зручними» абстракціями UFW і жорсткою фільтрацією пакетів nftables ви випадково
заблокували своє єдине з’єднання.
Це польовий посібник для реальних сценаріїв відмов: сюрпризи маршрутизації, помилки відстеження стану, прогалини у пересиланні трафіку
і класичний момент «Я дозволив порт VPN, то чому нічого не працює?». Ми діагностуємо швидко,
виправимо точно і допоможемо уникнути вивчення цих уроків опів на п’яту ранку.
Ментальна модель: що змінюється, коли з’являється VPN
VPN — це не лише «програма, яка шифрує трафік». На Linux це набір мережевих інтерфейсів, маршрутів, правил брандмауера
і часто змін DNS. Коли він піднімається, зазвичай відбуваються три речі, які можуть вас підвести:
-
Створюється новий інтерфейс (наприклад,
wg0,tun0), який стає новим шляхом для частини або всього трафіку.
Якщо ваш брандмауер специфічний до інтерфейсу (багато хто такий), ви щойно пересунули трафік з-під діючих правил. -
Змінюється маршрутизація (маршрут за замовчуванням, політична маршрутизація або маршрути по префіксу). Ваші відповіді можуть виходити іншим
інтерфейсом, ніж тим, на який прийшов запит. Conntrack не врятує вас від асиметричної маршрутизації, якщо ви собі в неї вистрелите. - Змінюються потреби в трансляції адрес (NAT/masquerade), коли трафік пересилається через хост або коли VPN призначає адреси, невідомі upstream-маршрутизаторам.
UFW і nftables не «розуміють VPN». Вони розуміють пакети, інтерфейси, стани і маршрути. Якщо ви налаштовуєте VPN і сподіваєтеся, що брандмауер «сам розбереться»,
ви ставите доступ на карту на основі надії.
Суха правда: більшість блокувань спричинені не однією поганою правилом. Це правильне правило, застосоване до
невірного інтерфейсу або в неправильному напрямку (INPUT проти OUTPUT проти FORWARD), в поєднанні з маршрутом, який ви не помітили,
що був замінений.
Цікаві факти та історичний контекст (щоб дивність стала зрозумілішою)
-
iptables був стандартом роками, але nftables — сучасна заміна; багато систем Ubuntu/Debian тепер виконують
команди iptables через бекенд nft без вашого відома. -
UFW — це фронтенд, спочатку створений, щоб зробити iptables доступнішим; він не відкриває всі нюанси фільтрації пакетів,
особливо щодо політичної маршрутизації та складного пересилання. -
Conntrack (відстеження стану) — це підсистема ядра, яка запам’ятовує потоки. Якщо ви забули дозволити
ESTABLISHED,RELATED,
ви блокуватимете відповіді навіть якщо початковий вхідний пакет був дозволений. -
WireGuard — це «просто UDP» з інтерфейсом у ядрі та криптоключовою маршрутизацією. Він не використовує окремий канал управління, як
багато старих VPN, що змінює вигляд «дозволеного трафіку». -
OpenVPN часто використовує пристрій tun/tap і може підсовувати маршрути та DNS. Якщо ви приймаєте pushed default route, ви легко
можете випадково спрямувати SSH-відповіді в тунель. -
Reverse path filtering (rp_filter) — це функція ядра проти підробки адрес, яка може скидати пакети, коли маршрути здаються асиметричними —
саме те, що деякі налаштування VPN створюють навмисно. -
Політична маршрутизація Linux (ip rule) існує десятиліттями. Клієнти VPN дедалі частіше використовують її для split tunneling, що означає,
що ваш «маршрут за замовчуванням» може не показувати повної картини. -
Поведінка «kill switch» (блокувати трафік поза VPN) — це скоріше політика брандмауера, ніж особливість VPN. Багато клієнтів
реалізують її правилами, які легко зробити неправильно.
Швидкий план діагностики
Коли ви втрачаєте зв’язок після увімкнення VPN (або трафік раптово зникає), у вас немає часу на філософські дебати про брандмауери. Перевірте це в порядку,
бо кожен крок швидко звужує область проблеми.
Перше: чи змінилася маршрутизація під вами?
- Подивіться маршрут за замовчуванням і правила політичної маршрутизації (
ip route,ip rule). - Підтвердіть, який інтерфейс використовує ваш IP джерела для доступу до вас (
ip route get). - Рішення: проблема маршруту чи брандмауера? Якщо відповіді виходять не тим інтерфейсом, спочатку виправляйте маршрути.
Друге: ви ріжете на INPUT/OUTPUT чи на FORWARD?
- Перевірте статус UFW і політики за замовчуванням (
ufw status verbose). - Перевірте набір правил nftables і лічильники ланцюгів (
nft list ruleset). - Рішення: блокування зазвичай відбувається в INPUT/OUTPUT; «VPN працює, але LAN за сервером не працює» — зазвичай FORWARD/NAT.
Третє: чи правильно працює conntrack/обробка станів?
- Переконайтеся, що прийняття established/related є в потрібних ланцюгах.
- Шукайте правила «drop invalid», що надто агресивні.
- Рішення: якщо відповіді блокуються, ви побачите SYN-и, які приходять, але SYN-ACK не виходить.
Четверте: чи rp_filter або sysctl не блокують асиметричні шляхи?
- Перевірте налаштування
rp_filterі підкоригуйте для випадків з VPN. - Рішення: якщо пакети приходять, але відкидаються до того, як лічильники брандмауера змінились, підозрюйте rp_filter.
П’яте: підтвердіть за допомогою захоплення пакетів, а не інтуїції
- Запустіть tcpdump на фізичній мережевій картці і на VPN-інтерфейсі одночасно.
- Рішення: якщо пакети заходять, але не виходять — брандмауер/маршрутизація. Якщо вони ніколи не заходять — проблема upstream/мережі.
Практичні завдання (команди, виводи, рішення)
Це точні вправи, які я виконую на Ubuntu/Debian, коли хтось каже «VPN вбив сервер». Кожне завдання включає
що зазвичай означає вивід і рішення, яке з нього випливає. Виконуйте їх з консолі, позанаправленого доступу
або існуючого SSH-сеансу, перш ніж чіпати щось інше.
Завдання 1: ідентифікуйте інтерфейси і що з’явилося разом із VPN
cr0x@server:~$ ip -brief link
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
ens3 UP 52:54:00:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
wg0 UNKNOWN 3a:2b:1c:0d:ee:ff <POINTOPOINT,NOARP,UP,LOWER_UP>
Значення: У вас є фізична NIC (ens3) і інтерфейс WireGuard (wg0).
Багато блокувань трапляються тому, що правила застосовані тільки до ens3.
Рішення: Якщо з’явився новий інтерфейс, аудитуйте правила брандмауера на предмет обмежень за інтерфейсом (iifname/oifname, правила UFW route).
Завдання 2: перевірте IP-адреси, щоб побачити задіяні мережі
cr0x@server:~$ ip -brief addr
lo UNKNOWN 127.0.0.1/8 ::1/128
ens3 UP 203.0.113.10/24 2001:db8:10::10/64
wg0 UNKNOWN 10.6.0.2/32
Значення: Публічна IP на ens3, VPN-адреса на wg0.
Зверніть увагу на /32 на WireGuard — звичне явище, але воно змінює очікування щодо маршрутів/NAT.
Рішення: Якщо ви очікуєте маршрутизувати інші підмережі через цей хост, потрібні явні маршрути і часто NAT.
Завдання 3: знайдіть маршрут за замовчуванням і чи перемістився він у VPN
cr0x@server:~$ ip route show
default dev wg0 scope link
203.0.113.0/24 dev ens3 proto kernel scope link src 203.0.113.10
10.6.0.0/24 dev wg0 proto kernel scope link src 10.6.0.2
Значення: Маршрут за замовчуванням тепер через wg0. Це full-tunnel налаштування.
Якщо ваш SSH-клієнт підключається до 203.0.113.10, запит приходить через ens3, але ваші відповіді можуть спробувати вийти через wg0.
Рішення: Якщо це сервер, яким ви керуєте дистанційно, не приймайте full-tunnel без явного прив’язування відповіді SSH або дозволу цього шляху. Розгляньте split tunnel або політичну маршрутизацію для трафіку управління.
Завдання 4: перевірте правила політичної маршрутизації (split tunnel часто тут)
cr0x@server:~$ ip rule show
0: from all lookup local
32764: from all fwmark 0xca6c lookup 51820
32766: from all lookup main
32767: from all lookup default
Значення: Частина трафіку помічена (fwmark 0xca6c) і використовує окрему таблицю маршрутизації. Це типовий випадок налаштувань wg-quick
для політичної маршрутизації або kill switch режимів.
Рішення: Якщо бачите мітки/правила, які ви не додавали, перевірте PostUp/PreDown hook-скрипти VPN-клієнта або systemd-юнити.
Ваш брандмауер має дозволяти помічений трафік виходити через правильний інтерфейс, інакше утворяться чорні діри.
Завдання 5: підтвердіть, яким маршрутом ядро відправить трафік до вашого адміністраторського IP
cr0x@server:~$ ip route get 198.51.100.25
198.51.100.25 dev wg0 src 10.6.0.2 uid 0
cache
Значення: Відповіді до вашої адмін-машини будуть виходити через wg0 з джерела 10.6.0.2.
Це класичний «SSH помирає після підняття VPN» сигнал.
Рішення: Додайте хост-маршрут або правило політичної маршрутизації, щоб трафік управління повертався через ens3, або відмовтесь від full-tunnel для серверів.
Завдання 6: перевірте статус 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
22/tcp ALLOW IN 198.51.100.0/24
51820/udp ALLOW IN Anywhere
Значення: Routed/forwarded трафік відключений. Це ламає налаштування «сервер маршрутизує LAN через VPN».
Також SSH дозволено тільки з певної підмережі; якщо ваш IP джерела змінюється при підключенні через корпоративний VPN або bastion, ви можете опинитись заблокованим.
Рішення: Якщо потрібне пересилання, увімкніть політику routed і додайте явні ufw route allow правила. Якщо потрібен стійкий доступ адміністрування,
залиште хоча б один відомий безпечний шлях (консоль, додаткова IP-адреса або ширша allowlist з MFA).
Завдання 7: подивіться, що фактично згенерував UFW (правила перед обробкою — там трапляється магія)
cr0x@server:~$ sudo grep -nE 'DEFAULT_FORWARD_POLICY|ufw-before-input|ufw-before-output|wg0|tun0' /etc/default/ufw /etc/ufw/before.rules
/etc/default/ufw:9:DEFAULT_FORWARD_POLICY="DROP"
/etc/ufw/before.rules:20:*filter
/etc/ufw/before.rules:28:-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Значення: Політика пересилання за замовчуванням — DROP. Conntrack established присутній (добре).
Рішення: Якщо ви плануєте маршрутизувати трафік через цей хост, змініть DEFAULT_FORWARD_POLICY і додавайте вузькі route-правила,
замість того, щоб робити все відкрите.
Завдання 8: перевірте набір правил nftables і політики ланцюгів (Ubuntu може використовувати nft під капотом)
cr0x@server:~$ sudo nft list ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iifname "lo" accept
tcp dport 22 ip saddr 198.51.100.0/24 accept
udp dport 51820 accept
counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Значення: Політика input — DROP, output — ACCEPT. Forward — DROP. Якщо ваш VPN потребує пересилання між інтерфейсами, це не спрацює.
Також SSH обмежено за джерелом; VPN може змінити те, що розуміється під «джерелом».
Рішення: Не чіпайте правила необачно. Спочатку підтвердіть, чи розірваний потік належить до INPUT, OUTPUT чи FORWARD, і лише потім додавайте найменш можливий accept.
Завдання 9: подивіться лічильники правил, щоб побачити, що відкидається
cr0x@server:~$ sudo nft -a list chain inet filter input
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
iifname "lo" accept
tcp dport 22 ip saddr 198.51.100.0/24 accept
udp dport 51820 accept
counter packets 41 bytes 2460 drop # handle 12
}
}
Значення: Лічильник drop рухається. Пакети приходять і відкидаються політикою за замовчуванням або фінальним правилом drop.
Рішення: Додайте тимчасове логування для drop-ів, або тимчасово дозволіть з вашого поточного джерела, щоб відновити доступ, а потім звузьте правила.
Завдання 10: підтвердіть, чи rp_filter не відкидає пакети до їх опрацювання брандмауером
cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.ens3.rp_filter net.ipv4.conf.wg0.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.ens3.rp_filter = 1
net.ipv4.conf.wg0.rp_filter = 1
Значення: Увімкнено strict-ish reverse path filtering. При асиметричній маршрутизації (поширена з VPN + публічним доступом) Linux може скидати
пакети, бо «найкращий шлях повернення» не збігається з вхідним інтерфейсом.
Рішення: Для мультигомованих/VPN-шлюзів встановіть rp_filter у 2 (loose) на відповідних інтерфейсах або обережно вимкніть там, де потрібно.
Робіть це свідомо; не відключайте контролі безпеки навмання.
Завдання 11: переконайтеся, що IP forwarding увімкнено, коли ви очікуєте маршрутизації
cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
Значення: Хост не форвардить IPv4 або IPv6 пакети. Навіть ідеальні правила брандмауера не змусять його маршрутизувати.
Рішення: Якщо цей хост має бути шлюзом (LAN→VPN, site-to-site і т.д.), увімкніть forwarding і збережіть у sysctl.
Завдання 12: перевірте, чи існує NAT/masquerade для вихідного VPN-трафіку
cr0x@server:~$ sudo nft list table ip nat
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
}
}
Значення: NAT-таблиця існує, але немає правила masquerade. Якщо ви пересилаєте приватний LAN через VPN, віддалена сторона може не знати, як повернутися.
Рішення: Додайте таргетований masquerade для джерела LAN, що виходить через wg0 (або краще: додайте маршрути на віддаленій боці, якщо ви ним керуєте).
Завдання 13: використайте tcpdump, щоб побачити, де потік вмирає
cr0x@server:~$ sudo tcpdump -ni ens3 tcp port 22 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:01:03.101234 IP 198.51.100.25.53122 > 203.0.113.10.22: Flags [S], seq 1234567890, win 64240, options [mss 1460], length 0
12:01:04.104567 IP 198.51.100.25.53122 > 203.0.113.10.22: Flags [S], seq 1234567890, win 64240, options [mss 1460], length 0
Значення: SYN-и приходять на ens3. Якщо ви не бачите SYN-ACK, що виходить на ens3, або брандмауер відкидає INPUT, або відповіді маршрутизуються кудись інде.
Рішення: Запустіть tcpdump також на wg0. Якщо SYN-ACK виходить через wg0, у вас проблема маршрутизації/політичної маршрутизації, а не з вхідним фільтром.
Завдання 14: перегляньте systemd-юнити та VPN PostUp хоки, що змінюють брандмауер/маршрути
cr0x@server:~$ systemctl status wg-quick@wg0 --no-pager
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/lib/systemd/system/wg-quick@.service; enabled; preset: enabled)
Active: active (exited) since Fri 2025-12-27 11:59:12 UTC; 3min ago
Docs: man:wg-quick(8)
man:wg(8)
Process: 1256 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
Значення: wg-quick задіяний. Він може додавати маршрути, ip rules та nft/iptables-сніпети залежно від конфігурації.
Рішення: Перегляньте /etc/wireguard/wg0.conf на предмет PostUp/PreDown команд та AllowedIPs, що можуть захоплювати маршрут за замовчуванням.
Завдання 15: перевірте логування UFW і недавні відмови ядра
cr0x@server:~$ sudo journalctl -k -g 'UFW BLOCK' -n 5 --no-pager
Dec 27 12:00:41 server kernel: [UFW BLOCK] IN=ens3 OUT= MAC=52:54:00:12:34:56 SRC=198.51.100.25 DST=203.0.113.10 LEN=60 TOS=0x00 PREC=0x00 TTL=51 ID=55233 DF PROTO=TCP SPT=53122 DPT=22 WINDOW=64240 SYN
Значення: UFW явно блокує вхідний SSH з вашого поточного джерела. Це не «VPN його зламав»; ваш allowlist став неправильним.
Рішення: Тимчасово розширте доступ до SSH з безпечного діапазону або через jump host, відновіть контроль, а потім спроєктуйте доступ так, щоб він пережив зміни VPN.
Завдання 16: аварійний страховий механізм — заплануйте відкат правил брандмауера
cr0x@server:~$ echo "ufw disable" | sudo at now + 2 minutes
warning: commands will be executed using /bin/sh
job 7 at Fri Dec 27 12:04:00 2025
Значення: Ви запланували автоматичне відключення UFW через 2 хвилини. Якщо ви себе заблокуєте, сервер врешті повернеться.
Рішення: Використовуйте це перед ризикованими змінами брандмауера на віддалених системах. Скасуйте завдання після перевірки з’єднання.
Жарт №1: Брандмауери — як ремені безпеки: поки не спробуєш вилізти у вікно, коли машина їде.
Поширені помилки: симптом → причина → виправлення
1) «SSH відмирає одразу після підняття VPN»
Симптоми: Існуючий SSH-сеанс зависає; нові підключення таймаутяться; VPN-інтерфейс піднято коректно.
Корінь проблеми: Маршрут за замовчуванням перемістився на wg0/tun0, тож відповіді SSH йдуть у тунель з невірним IP джерела; або rp_filter відкидає асиметричний трафік.
Виправлення: Закріпіть маршрути управління через публічний інтерфейс або використайте політичну маршрутизацію, щоб трафік до адміністраторської підмережі використовував ens3. Встановіть rp_filter у loose там, де потрібно.
cr0x@server:~$ sudo ip route add 198.51.100.0/24 via 203.0.113.1 dev ens3
cr0x@server:~$ sudo sysctl -w net.ipv4.conf.ens3.rp_filter=2
net.ipv4.conf.ens3.rp_filter = 2
2) «VPN підключається, але нічого не виходить в інтернет»
Симптоми: Тунель піднято; handshake працює; DNS може резолвитись; вихідного трафіку нема.
Корінь проблеми: Kill switch або занадто жорсткий OUTPUT, що блокує все, окрім порту VPN UDP. Часто з політикою «deny outgoing» без whitelist для wg0.
Виправлення: Дозвольте вихід на VPN-інтерфейсі і зберігайте OUTPUT станом. Якщо UFW, додайте явні allow out правила і перевірте вибір таблиці маршрутів.
cr0x@server:~$ sudo ufw allow out on wg0
Rule added
3) «WireGuard handshake працює, але трафік не проходить»
Симптоми: wg show показує оновлений час останнього handshake; ping/ssh через тунель не працюють.
Корінь проблеми: Несумісність AllowedIPs, відсутні маршрути або брандмауер блокує FORWARD між інтерфейсами; іноді проблеми MTU/PMTU, але почніть з маршрутів/правил.
Виправлення: Перевірте AllowedIPs і маршрути; дозвольте форвард; забезпечте NAT при потребі.
cr0x@server:~$ sudo wg show wg0
interface: wg0
public key: 3m...redacted...9Q=
listening port: 51820
peer: 8A...redacted...k=
endpoint: 192.0.2.50:51820
allowed ips: 10.6.0.0/24
latest handshake: 1 minute, 4 seconds ago
transfer: 92.14 KiB received, 88.22 KiB sent
4) «Мій VPN працює для самого хоста, але клієнти не дістають LAN за ним»
Симптоми: Сервер може пінгувати через тунель; клієнти підключаються; клієнти не дістають внутрішніх підмереж.
Корінь проблеми: Ланцюг FORWARD має політику drop (UFW «routed disabled»), IP forwarding вимкнено, відсутній masquerade або відсутні маршрути на стороні LAN.
Виправлення: Увімкніть IP forwarding; змініть політику UFW для пересилань; додайте ufw route allow; додайте таргетований NAT або маршрути на LAN-маршрутизаторі.
5) «UFW каже, що дозволяє 51820/udp, але VPN все одно не підключається»
Симптоми: Клієнт не може зробити handshake; сервер нічого не показує; UFW виглядає «правильним».
Корінь проблеми: Правило існує в IPv4, але не в IPv6 (або навпаки); endpoint використовує v6; або nftables активний з іншим набором правил, ніж ви думаєте.
Виправлення: Перевірте адреси прослуховування; перевірте обидві адресні сімейства; підтвердьте фактичний бекенд брандмауера; тестуйте через tcpdump на NIC.
6) «Усе працювало… поки я не увімкнув UFW»
Симптоми: VPN працює без брандмауера; ламається з увімкненим; часто ламає пересилання.
Корінь проблеми: За замовчуванням UFW: routed traffic disabled; відсутні ufw route правила; занадто специфічні правила по інтерфейсу; відсутній дозвіл для VPN-інтерфейсу.
Виправлення: Ставтеся до пересилання як до окремого продукту. Налаштуйте DEFAULT_FORWARD_POLICY, додайте явні route-правила і тестуйте потоки end-to-end.
7) «DNS ламається тільки коли VPN увімкнений»
Симптоми: Можете пінгувати IP; імена не резолвяться; або резолюція повільна/нестабільна.
Корінь проблеми: VPN клієнт штовхає DNS; systemd-resolved змінює upstream; брандмауер блокує UDP/TCP 53 на невірному інтерфейсі; або ви спрямували весь трафік у тунель, а DNS за його межами.
Виправлення: Визначте, де має жити DNS (всередині VPN чи поза ним). Потім дозвольте його явно і перевірте resolvectl та маршрути до DNS-серверів.
8) «Після додавання “простого” набору правил nftables UFW перестав працювати»
Симптоми: Команди UFW успішні, але поведінка не відповідає; лічильники не рухаються там, де очікували.
Корінь проблеми: Конкуруючі набори правил або пріоритети ланцюгів. UFW може керувати власними таблицями/ланцюгами; ваші кастомні правила можуть їх затінювати або застосовуватися раніше.
Виправлення: Оберіть один контролер. Або керуйте nftables напряму (і вимкніть UFW), або дозвольте UFW володіти фільтрацією і додавайте лише підтримувані хуки.
Три корпоративні міні-історії з поля
Міні-історія №1: інцидент через неправильне припущення
Середня компанія мала невеликий парк Ubuntu-шлюзів, що завершували site-to-site VPN. Команда додала WireGuard,
щоб замінити старий OpenVPN. План міграції виглядав чистим: підняти wg0, дозволити UDP 51820 inbound,
і все.
Неправильне припущення було тонким: «Якщо handshake працює, plane даних теж працюватиме». Handshake дійсно працював. Графіки здавались обнадійливими. Потім внутрішні користувачі почали скаржитись, що доступні лише деякі адреси.
Інженер на виклику бачив «latest handshake: 30 seconds ago» і марно чіплявся за MTU- фантоми.
Насправді проблема була в пересиланні. UFW мав routed відключений. Сам сервер міг дістати віддалені підмережі, бо OUTPUT дозволений,
але пакети з LAN відкидались у FORWARD. VPN не був зламаний; не працювала функція шлюзу.
Виправлення не було героїчним. Вони увімкнули IP forwarding, встановили політику пересилання UFW і додали вузькі маршрути:
лише внутрішня підмережа до підмережі VPN, лише через wg0. Раптом усе запрацювало, і наратив «WireGuard ненадійний» тихо вмер.
Міні-історія №2: оптимізація, що відплатилася
Інша організація стандартизувала nftables і хотіла «чисті, мінімальні правила». Хтось переписав серверний брандмауер як
єдиний ruleset з policy drop і лише кількома accept: SSH, порт VPN і established/related. Вони також
звузили OUTPUT до whitelist, бо «сервери не повинні говорити в інтернет».
Оптимізація полягала у видаленні того, що здавалося зайвим, і сподіванні, що «в нас лише кілька сервісів». Вона працювала в стейджингу. У продакшні була одна додаткова деталь: VPN-клієнт використовував політичну маршрутизацію і fwmark-и, а резолвер DNS стояв поза шляхом VPN. OUTPUT почав блокувати DNS і keepalive- повідомлення VPN таким чином, що це не було очевидно з початкового огляду правил.
Режим відмови не був повним простою; він був гіршим — непередбачувана поведінка. Деякі запити проходили, коли кеші були гарячими, потім падали після спливу TTL. Люди звинувачували VPN-провайдера, потім DNS, потім «Linux мережі». Класика.
Виправлення — припинити передчасні оптимізації і змоделювати потоки. Вони створили явні OUTPUT-дозволи для VPN-інтерфейсу,
для DNS до обраних резолверів і для NTP. Також додали лічильники та логування для фінального drop, бо мовчазний drop — рецепт для тижневого інциденту.
Міні-історія №3: нудна, але правильна практика, що врятувала день
Фінансова команда підтримувала Debian bastion-хости зі строгими політиками брандмауера і обов’язковим VPN для доступу адміністраторів.
Вони мали правило: будь-яка зміна брандмауера/VPN повинна включати автоматичний таймер відкату і план позанаправленого доступу.
Нікого це не тішило. Всі виграли від цього правила.
Під час вікна змін інженер підкоригував правила UFW, щоб запровадити kill switch VPN. Очікувана поведінка: дозволяти вихідний трафік лише на wg0, блокувати все інше. Застосували зміну і миттєво втратили SSH-сеанс.
Передбачувано, але стресово.
Через дві хвилини запланований відкат спрацював і UFW вимкнувся. SSH повернувся. Жодних панічних дзвінків у дата-центр,
жодних «може хто перезавантажить», жодних ризикових напів-редагувань через напівміертвий сеанс. Вони перепідключились, виправили виключення політичної маршрутизації для підмережі управління і повторили — цього разу з тестуванням.
Нудна практика, велика віддача. Вона також змінила культуру команди: люди стали охочіше покращувати безпеку, бо план відновлення усунув страх.
Жарт №2: Найшвидший спосіб довести, що у вас є брандмауер — випадково продемонструвати його на самому собі.
Чеклісти / покроковий план (безпечні розгортання)
Чекліст A: Перш ніж увімкнути VPN на віддаленому сервері
- Отримайте шлях відновлення. Консоль, IPMI, серійна консоля хмари або хоча б другий SSH-шлях з іншої мережі.
- Заплануйте автоматичний відкат. Використайте
at, щоб через 2–5 хвилин відключити UFW або відновити nftables. - Зробіть знімок конфігурації. Скопіюйте
/etc/ufw, nft правила і конфіги VPN у безпечне місце. - Запишіть IP-адреси ваших джерел управління. Якщо ваша IP змінюється через корпоративний VPN, ваш allowlist зрадить вас.
- Вирішіть full tunnel чи split tunnel. Сервери рідко хочуть повний тунель; будьте явними щодо винятків.
Чекліст B: Якщо вам потрібен kill switch VPN (і потрібен SSH)
- Дозвольте вхідний SSH на фізичний інтерфейс із довірених діапазонів.
- Дозвольте вихідні відповіді управління через фізичний інтерфейс (політична маршрутизація/host routes).
- Дозвольте вихід на VPN-інтерфейсі широко, потім звузьте цільові кінцеві точки за потреби.
- Зберігайте
established,relatedу INPUT/OUTPUT. - Додайте логування/лічильники на фінальних drop-ах, щоб бачити, що ви зламали.
Чекліст C: Якщо хост — VPN-шлюз для інших мереж
- Увімкніть
net.ipv4.ip_forward=1(і IPv6 forwarding якщо потрібно). - Вирішіть NAT чи маршрутизовані підмережі (надавайте перевагу маршрутам, якщо контролюєте обидві сторони).
- Явно дозволіть FORWARD потоки (LAN → VPN, VPN → LAN за потреби).
- Переконайтесь, що зворотні маршрути існують з обох боків (NAT приховує це; маршрути потребують їх наявності).
- Тестуйте з клієнта за шлюзом, а не тільки з самого шлюзу.
Таймер відкату: скасуйте його, коли будете в безпеці
cr0x@server:~$ atq
7 Fri Dec 27 12:04:00 2025 a root
cr0x@server:~$ sudo atrm 7
Значення: Ви видаляєте заплановане завдання відкату після підтвердження, що можете перепідключитись.
Рішення: Не скасовуйте зарано. Чекайте, поки перевірите з нового сеансу.
Практичні патерни: kill switch, split tunnel, пересилання на сервері
Патерн 1: тримайте трафік управління поза VPN (рекомендовано для серверів)
Якщо сервер має публічну IP і ви адмініструєте його по SSH, ставте управління як окрему контрольну площину.
Не кидайте його у full-tunnel VPN, якщо ви не готові точно спроєктувати маршрути.
Найпростішим стабільним підходом є: VPN обробляє трафік додатків або конкретні підмережі, але відповіді SSH завжди виходять
тим інтерфейсом, куди прийшов SSH.
Практично це означає або:
(a) не змінювати маршрут за замовчуванням при піднятті VPN; додайте специфічні маршрути для VPN-цілей; або
(b) використовувати політичну маршрутизацію, щоб лише обраний трафік ішов через VPN.
Патерн 2: розумний kill switch, що не вбиває доступ
Kill switch — це просто «відкидати все, що не йде через wg0/tun0». Небезпечна частина в тому, що ваш SSH-сеанс теж стане «все»,
якщо ви не виріжете для нього винятки.
Правильний виняток — не «дозволити порт 22». Це «підтвердити, що відповіді до моїх адмін-мереж маршрутизуються і проходять через правильний інтерфейс,
навіть коли маршрут за замовчуванням — VPN». Це маршрутизація плюс фільтрація, а не лише фільтрація.
Патерн 3: VPN-шлюз для LAN (форвард + NAT або маршрути)
Це область, де UFW дивує людей. За замовчуванням UFW ставиться до routed traffic консервативно. Це нормально.
Але якщо ви будуєте шлюз, потрібно явним чином налаштовувати пересилання.
Якщо ви не контролюєте маршрути на віддаленій стороні, NAT — прагматичне рішення. Якщо контролюєте обидві сторони, маршрутизовані підмережі чистіші.
NAT приховує вихідні IP; маршрути зберігають їх, але потребують реальних записів/оголошень маршрутів.
Увімкніть forwarding (персистентно)
cr0x@server:~$ sudo tee /etc/sysctl.d/99-vpn-forwarding.conf >/dev/null <<'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
cr0x@server:~$ sudo sysctl --system
* Applying /etc/sysctl.d/99-vpn-forwarding.conf ...
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
Значення: Ядро тепер форвардить пакети.
Рішення: Робіть це тільки на хостах, які призначені для маршрутизації; це змінює безпекову позицію.
UFW: дозволити routed трафік між LAN і VPN (приклад)
cr0x@server:~$ sudo ufw route allow in on ens3 out on wg0 from 192.168.50.0/24 to 0.0.0.0/0
Rule added
cr0x@server:~$ sudo ufw route allow in on wg0 out on ens3 from 0.0.0.0/0 to 192.168.50.0/24
Rule added
Значення: Ви дозволили форвард обома напрямками для тієї LAN-підмережі.
Рішення: Звужуйте кінцеві точки, якщо можете. «LAN → будь-куди» підходить для виходу в інтернет, але не для внутрішнього east-west у корпоративних мережах.
nftables: таргетований masquerade для LAN через wg0 (приклад)
cr0x@server:~$ sudo nft add table ip nat
cr0x@server:~$ sudo nft 'add chain ip nat postrouting { type nat hook postrouting priority srcnat; policy accept; }'
cr0x@server:~$ sudo nft add rule ip nat postrouting oifname "wg0" ip saddr 192.168.50.0/24 masquerade
Значення: Клієнти LAN будуть виглядати для віддаленої сторони як IP інтерфейсу VPN, що спрощує зворотну маршрутизацію.
Рішення: Якщо потрібен аудит по хостах, надавайте перевагу маршрутизації підмереж замість NAT.
Закріпіть трафік управління політичною маршрутизацією (приклад)
Якщо VPN настоює на володінні маршрутом за замовчуванням, ви все ще можете зберегти управління стабільним, використавши окрему таблицю маршрутів
для трафіку до ваших адмін-мереж.
cr0x@server:~$ echo "100 mgmt" | sudo tee -a /etc/iproute2/rt_tables
100 mgmt
cr0x@server:~$ sudo ip route add default via 203.0.113.1 dev ens3 table mgmt
cr0x@server:~$ sudo ip rule add to 198.51.100.0/24 lookup mgmt priority 1000
Значення: Трафік до вашої адмін-підмережі використовує фізичний шлюз, навіть якщо в основній таблиці default вказує на VPN.
Рішення: Це дорослий підхід, коли потрібно поєднати full-tunnel з віддаленим управлінням.
Одна цитата про надійність (парафразована думка)
«Надія — не стратегія.» — парафразована думка з культури операцій/принципів SRE (поширена у розмовах про надійність)
Ця фраза всюди з’являється, бо вона влучно застосовна до змін у брандмауері на віддалених машинах.
UFW проти nftables: оберіть отруту, уникайте мішання метафор
UFW: підходить для простих політик, небезпечний, коли ви вважаєте, що він покриває форвард за замовчуванням
UFW зручний, коли ваші потреби: дозволити SSH, дозволити кілька портів, заборонити все інше. Він позбавляє вас писати 200 рядків правил для простого policy.
Це плюс.
Де UFW підводить інженерів — це routed traffic і шляхи VPN по інтерфейсу. Якщо система працює як шлюз,
потрібно мислити про FORWARD. UFW дозволяє це, але не змушує вас думати. Оце і є пастка.
nftables: явна сила, явні наслідки
nftables чистий і виразний. Він також робить саме те, що ви йому наказали, навіть якщо це самонанесена відмова. З nftables вам варто відчути себе комфортно з:
- Політиками ланцюгів (
policy dropозначає, що потрібні явні accepts). - Обробкою станів (
ct state established,relatedв більшості дизайнів — не опціонально). - Збігом по інтерфейсу (
iifname/oifname) — особливо для VPN-інтерфейсів. - Лічильниками і логуванням (мовчазний drop — фабрика інцидентів).
Не призначайте двох капітанів для одного корабля
Якщо UFW активний і ви також завантажуєте кастомний набір правил nftables, ви можете опинитися з перекриваючимися таблицями та пріоритетами ланцюгів.
Іноді це працює випадково. Це не дизайн.
Оберіть одне:
тримайте UFW для політик, або керуйте nftables напряму і вимкніть UFW. Мішання — це шлях до набору правил, який ніхто на виклику не зрозуміє.
Аудитуйте, хто фактично володіє фільтрацією пакетів на вашому хості
cr0x@server:~$ sudo ufw status
Status: active
cr0x@server:~$ sudo systemctl is-active nftables
inactive
cr0x@server:~$ sudo update-alternatives --display iptables | sed -n '1,6p'
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
Значення: UFW активний; nftables.service може бути inactive. Однак iptables команди можуть мапитись на бекенд nft. Навіть якщо nftables.service inactive, nft може бути підкладним рушієм.
Рішення: При відлагодженні завжди інспектуйте nft list ruleset як джерело істини на сучасних системах.
FAQ
1) Чому дозвіл порту UDP VPN нічого не виправив?
Тому що UDP-порт покриває тільки зовнішній транспорт тунелю. Ваш реальний трафік йде через інший інтерфейс
(wg0/tun0), потрапляє в інші ланцюги (FORWARD/OUTPUT) і може потребувати NAT або маршрутів.
2) Чому SSH ламається тільки після того, як VPN змінив маршрут за замовчуванням?
Бо відповіді слідують таблиці маршрутів. Якщо відповіді виходять через VPN, змінюється IP джерела і клієнт не приймає його
(або шлях його відкидає). Виправляйте, закріплюючи маршрути управління або за допомогою політичної маршрутизації.
3) Чи можна просто встановити UFW за замовчуванням allow outgoing і забути?
На простому сервері, можливо. На VPN-шлюзі або при налаштуванні kill-switch — ні. Обмеження OUTPUT взаємодіють з маршрутизацією VPN,
DNS і keepalive-ами неочевидним чином. Якщо ви обмежуєте OUTPUT, робіть це з явними дозволами і лічильниками.
4) Який найчистіший спосіб уникнути блокувань під час змін брандмауера?
Заплануйте таймер відкату (at now + 2 minutes), застосуйте зміну, протестуйте з нового сеансу, потім скасуйте таймер.
Також зберігайте доступ до консолі, якщо машина важлива.
5) Чому WireGuard показує handshakes, але все одно немає зв’язку?
Успішний handshake доводить, що піри можуть обмінюватися ключами по UDP. Це не доводить, що ваші маршрути, AllowedIPs, політика пересилання
або NAT коректні. Ставтеся до цього як до «транспорт живий», а не «мережа завершена».
6) Чи потрібен мені NAT для трафіку VPN?
Якщо ви пересилаєте приватний LAN через VPN і віддалена сторона не має маршруту назад до цієї LAN, NAT — практичне вирішення.
Якщо ви контролюєте обидві сторони, надавайте перевагу маршрутам і уникайте NAT для кращої видимості і менше сюрпризів.
7) Чому IPv6 ускладнює ситуацію?
Бо можна випадково дозволити IPv4 і блокувати IPv6 (або навпаки), і клієнт обере ту сімейство, що «працює».
Потім воно ламається. Аудитуйте сокети прослуховування і правила брандмауера для обох сімейств, якщо IPv6 увімкнено.
8) Чи безпечно вимикати rp_filter?
rp_filter допомагає запобігати підробці адрес. Вимикати його навмання — лінь. Для VPN-шлюзів і асиметричної маршрутизації встановіть його в loose режим
(2) на відповідних інтерфейсах, щоб легітимний асиметричний трафік не відкидався.
9) Варто використовувати UFW чи рідний nftables для VPN-систем?
Якщо система проста, UFW підходить. Якщо вам потрібна політична маршрутизація, складне пересилання, кілька VPN або жорсткі kill-switch-и,
nftables зазвичай більш зрозумілий, бо ви можете точно виразити намір — за умови, що ваша команда вміє ним керувати.
10) Яка найпоширеніша помилка UFW з VPN-шлюзами?
Забути, що routed traffic вимкнений за замовчуванням. Ви можете весь день дозволяти порт VPN; форвард все одно не відбудеться.
Виправлення: увімкніть forwarding і додайте ufw route allow правила.
Висновок: наступні кроки, що збережуть вам доступ
Повторювана тема — приземлена: VPN змінює маршрути та інтерфейси, а ваш брандмауер не враховує ваших намірів.
Якщо ви розглядаєте «підключення VPN» як проблему відкриття порту, ви будете продовжувати блокувати себе.
Наступні кроки, які я насправді зробив би на production Ubuntu/Debian хості:
- Визначте, чи сервер має бути full-tunnel чи split-tunnel. Якщо це віддалено адміністрований сервер, за замовчуванням — split-tunnel.
- Впровадьте звичку таймера відкату для кожної зміни брандмауера на віддалених системах.
- Аудитуйте маршрути (
ip route,ip rule) і явно підтверджуйте шляхи повернення для управління. - Оберіть одну систему управління брандмауером (UFW або nftables) і припиніть їх мішати, якщо не любите археологію.
- Додайте лічильники/логування до правил drop, щоб відлагодження було на підставі доказів, а не ритуалів.
Якщо ви зробите тільки одну річ: зробіть ip route get рефлексом перед і після підняття VPN. Воно скаже вам, куди підуть ваші відповіді.
Це різниця між «безпечним сервером» і «безпечним, але недоступним сервером».