WireGuard роздільний тунель: маршрутуйте лише те, що потрібно (і залишайте решту локально)

Було корисно?

Роздільний тунель — це те, що ви робите, коли «VPN для всього» ламає щось, чим ви реально користуєтесь: локальний принтер, гостьовий Wi‑Fi з captive portal, відеодзвінки,
хмарне IDE, бюджет затримки або ваш спокій. Фокус — змусити WireGuard передавати лише трафік, який має бути приватним або доступним,
в той час як усе інше залишається у звичайній мережі — без випадкових витоків, чорних дір або дивного напівпрацюючого DNS.

Якщо ви колись бачили, як розробник «вирішує» роздільний тунель, поставивши AllowedIPs = 0.0.0.0/0 і оголосивши справу закритою, ви вже знаєте, чим це закінчиться:
інцидент у понеділок вранці з великою кількістю здивувань і однією дуже впевненою хибною припущенням.

Ментальна модель: чим насправді є роздільний тунель у WireGuard

WireGuard — це VPN, але він поводиться скоріше як «захищений віртуальний Ethernet‑кабель із мозком маршрутизації», ніж класичний пристрій повного тунелю.
Тут немає «нагодження маршрутів» як у деяких старих VPN‑стеках; WireGuard в основному виконує те, що ви налаштували локально: ви створюєте інтерфейс,
додаєте peers, і ваша ОС відправляє пакети в цей інтерфейс на основі звичайних правил маршрутизації.

Роздільний тунель — це не стільки функція WireGuard, скільки рішення на рівні маршрутизації:

  • Повний тунель: більшість або весь трафік іде через VPN‑інтерфейс (дефолтний маршрут через wg0).
  • Роздільний тунель: лише певні префікси призначення (підмережі/IP) використовують VPN; усе інше використовує звичайний дефолтний маршрут.
  • Селективна та політична маршрутизація: певні джерела (додатки/користувачі/марки) використовують VPN; інші — ні (більш просунуто, дуже корисно).

Конфігурація WireGuard зв’язує ідентичність і маршрутизацію через AllowedIPs в секції peer. Цей параметр одночасно:
(1) визначає, які IP‑адреси призначення слід надсилати цьому peer, і (2) визначає, які IP‑адреси джерела вважаються дійсними від цього peer.
Це елегантно. Але також причина, чому «маленька» зміна може тихо переписати вашу таблицю маршрутів.

Надійний спосіб думати про це:
«Коли я відправляю пакет до X, який peer у AllowedIPs претендує на X?»
Якщо відповідь «жоден», пакет іде через звичайний інтерфейс. Якщо відповідь «peer», пакет йде в WireGuard.
Якщо відповідь «більше ніж один», ви зробили фатальну помилку, і ядро вибере «найкраще співпадіння», яке може не відповідати вашим очікуванням.

Суха істина: роздільний тунель часто ламається не тому, що WireGuard складний, а тому що маршрутизація безжальна, а DNS примхливий.

Цікаві факти та трохи історії (бо це має значення)

Конкретні контекстні пункти, що пояснюють, чому роздільний тунель WireGuard виглядає так, як він виглядає:

  1. WireGuard був спроєктований бути компактним. Реалізація в Linux відома своєю компактністю порівняно зі старішими VPN‑стеками, що зменшує поверхню атаки і несподіванки.
  2. За замовчуванням використовуються сучасні криптографічні вибори. Ви не витрачаєте день на дискусії про набори шифрів; натомість витрачаєте його на маршрутизацію та операції (краще використання ресурсу).
  3. «AllowedIPs» — це і маршрутизація, і контроль доступу. Це не типово для багатьох VPN, де інжекція маршрутів і ACL розділені. Це потужно, але гостро.
  4. WireGuard покладається на UDP. Це добре для продуктивності; іноді дратує в мережах, які «допомагають» блокуючи або пошкоджуючи UDP.
  5. Немає вбудованої концепції «сервер» проти «клієнта». Кожен peer — просто peer. Організаційна ієрархія протоколу не вражає.
  6. Прохід через NAT — це перша класна функція. Роумінг клієнтів працює добре, бо WireGuard відстежує endpoints і може оновлювати їх після дійсного пакета.
  7. wg-quick навмисно висловлює думку. Він додає маршрути, налаштовує фаєрвол (залежно від ваших хук‑скриптів) і намагається швидко забезпечити «роботу» — іноді надто швидко для складних роздільних тунелів.
  8. UX роздільного тунелю на Android/iOS з’явився пізніше, ніж протокол. Протокол ніколи не переймався; клієнтам довелося додати перемикачі та списки виключень з часом.
  9. Роздільний тунель старший за WireGuard. Підприємства робили «маршрутувати лише корпоративні підмережі» з часів IPsec; різниця в тому, що WireGuard робить список маршрутів явним і локальним.

AllowedIPs: важіль, який рухає маршрути (і іноді ваші нерви)

На стороні клієнта роздільний тунель зазвичай просто означає «не встановлюйте дефолтний маршрут через wg0».
Переклад: не ставте 0.0.0.0/0::/0) у AllowedIPs.
Помістіть лише ті підмережі, які вам реально потрібні.

Приклад: ви хочете доступ до внутрішніх сервісів у 10.40.0.0/16 і приватної бази даних 172.20.10.5/32.
Ваша конфігурація peer стає:

cr0x@server:~$ cat /etc/wireguard/wg0.conf
[Interface]
Address = 10.99.0.2/32
PrivateKey = <client-private-key>
DNS = 10.40.0.53

[Peer]
PublicKey = <server-public-key>
Endpoint = vpn-gw.example:51820
AllowedIPs = 10.40.0.0/16, 172.20.10.5/32
PersistentKeepalive = 25

Важлива частина — що робить wg-quick з цим: він встановлює маршрути ядра для тих префіксів через wg0.
Усе інше використовує ваш дефолтний маршрут (зазвичай шлюз Wi‑Fi або Ethernet).

Що з «AllowedIPs = 10.99.0.0/24» на сервері?

На стороні сервера AllowedIPs стосується того, які IP сервер приймає від peer і куди він буде надсилати відповіді назад до цього peer.
Для типової road‑warrior установки кожен клієнт отримує один /32 всередині VPN (наприклад 10.99.0.2/32), і в секції peer сервера вказується цей /32.
Таким чином сервер знає, куди надсилати зворотний трафік для VPN‑адреси цього клієнта.

Для site‑to‑site AllowedIPs на сервері може включати цілі LAN‑підмережі за peer, але тоді ви будуєте реальну маршрутизовану мережу.
Робіть це навмисно. Документуйте. Старайтесь ставитися до цього як до продакшн‑маршрутизації, бо це так і є.

Жарт #1 (коротко, по темі): Маршрутизація як офісна політика — усе працює, доки хтось не заявить, що володіє всім будинком.

Шаблони проєктування для реальних роздільних тунелів

Шаблон A: «Лише корпоративні підмережі» (класичний роздільний тунель)

Ви маршрутуєте лише RFC1918 внутрішні діапазони, які реально використовуються корпоративними сервісами. Не 10.0.0.0/8, якщо ви цього не маєте на увазі.
Будьте точними. Люди люблять займати IP‑простір як вільну нерухомість.

Добре:

  • AllowedIPs = 10.40.0.0/16, 10.41.12.0/24

Підозрило:

  • AllowedIPs = 10.0.0.0/8 (ймовірно, ви не володієте всім цим простором)
  • AllowedIPs = 0.0.0.0/0 (це — повний тунель, незалежно від назв)

Шаблон B: «Один сервіс лише» (найточніший роздільний тунель)

Ви маршрутуєте кілька /32 (або малі підмережі) лише для точних сервісів: Git‑хост, менеджер секретів, внутрішній API‑шлюз.
Чудово для підрядників, CI‑ране́рів і «я не довіряю цьому ноутбуку» ситуацій.

Компроміс: потрібно підтримувати список в актуальному стані. IP змінюються, сервіси переїжджають, хтось додає новий регіон — і раптом «VPN не працює».
Насправді він не «не працює». Ваша маршрутизація застаріла.

Шаблон C: «Політична маршрутизація» (маршрутизація за джерелом)

Іноді ви хочете, щоб трафік від конкретного користувача або контейнерної мережі йшов через WireGuard, у той час як решта хоста залишалася локальною.
Це не стільки про AllowedIPs, скільки про політичну маршрутизацію Linux (ip rule + кастомні таблиці) і, можливо, fwmarks.
wg-quick може робити частину цього, але багато продакшн‑сценаріїв роблять це явно.

Шаблон D: «Виключити локальну LAN» (майже повний тунель з винятками)

Деякі клієнти (особливо мобільні) хочуть повний тунель для приватності, але все одно потребують доступу до локальної LAN (принтери, Chromecast, NAS тощо).
Це «дефолтний маршрут через VPN, але додайте явні маршрути для локальних підмереж через місцевий шлюз».

Це може працювати. Також може створити дивну асиметрію, коли локальні пристрої намагаються відповісти на ваш VPN‑призначений source IP. Якщо ви це робите,
використовуйте NAT на клієнті або уникайте вихідного трафіку з VPN‑адреси до LAN‑пристроїв.

DNS у роздільних тунелях: не витікати, не ламати

DNS — це місце, куди роздільні тунелі тихо йдуть на смерть. Ви правильно маршрутували 10.40.0.0/16, але клієнт все ще питає кофешоповий резолвер
про jira.corp. Звісно, це провалюється. Або гірше: публічний резолвер повертає щось несподіване, і ви підключаєтесь не туди.

Стратегії DNS для роздільних тунелів, в порядку зростання операційної зрілості:

1) «Просто вкажіть DNS = корпоративний резолвер»

Проста опція: DNS = 10.40.0.53 в конфігурації інтерфейсу WireGuard. Коли тунель піднятий, ваш резолвер стає корпоративним.
Недолік: це може зламати локальне дозвіл імень (доменів captive portal готелів, особливостей split‑horizon) і може уповільнити все, якщо корпоративний резолвер далеко.

2) Split DNS (маршрувати лише певні домени через корп)

На Linux з systemd-resolved ви можете налаштувати per‑interface routing domains. Тобто *.corp йде до VPN‑резолвера,
а все інше залишається локальним. Це золота середина для багатьох організацій.

3) Локальний stub‑резолвер, який форвардить корпоративні зони через VPN

Ви запускаєте локальний резолвер (або використовуєте існуючий) і форвардите внутрішні зони на VPN‑DNS‑сервер, з кешуванням і розумними таймаутами.
Це нудне рішення. Воно працює. І робить налагодження менш театральним.

Парафразована надійна ідея від John Allspaw: «Надійності ви не отримуєте надією; ви отримуєте її, проектуючи та практикуючи відмови».
Split DNS — ідеальний приклад — проєктуйте його, не надійтесь, що все саме по собі вирішиться.

Практичні завдання (команди, виводи, рішення)

Це частина, де ми припиняємо милуватися протоколом і починаємо допитувати систему.
Кожне завдання нижче містить: команду, реалістичний вивід, що це означає і яке рішення прийняти далі.

Завдання 1: Підтвердити, що тунель реально підключений (а не «налаштований, але мертвий»)

cr0x@server:~$ sudo wg show
interface: wg0
  public key: 2pQ2c2fWmGm6l5qgkq8n8fZ4xX9o7u1nJt4XxR9gQhE=
  private key: (hidden)
  listening port: 51820

peer: Hx2e1F0rQyQH7cQqX2o3v9KQ0m7E4uE3r4Y8z8u4L0w=
  endpoint: 203.0.113.50:53211
  allowed ips: 10.99.0.2/32
  latest handshake: 42 seconds ago
  transfer: 88.31 MiB received, 12.04 MiB sent
  persistent keepalive: every 25 seconds

Значення: Handshake свіжий і байти передаються. Криптографія в порядку; якщо додатки все ще не працюють — дивіться маршрутизацію/DNS/MTU.

Рішення: Якщо latest handshake — «never» або дуже давній, переходьте до перевірки фаєрволу/NAT/endpoint перед тим, як торкатися маршрутів.

Завдання 2: Перевірити, які маршрути встановив wg-quick

cr0x@server:~$ ip route show table main | grep wg0
10.40.0.0/16 dev wg0 proto static scope link
172.20.10.5 dev wg0 proto static scope link

Значення: Через wg0 маршрутизуються лише передбачені префікси. Це чистий роздільний тунель.

Рішення: Якщо ви бачите default dev wg0 і не хотіли повний тунель — виправте AllowedIPs негайно.

Завдання 3: Перевірити, що дефолтний маршрут залишається локальним

cr0x@server:~$ ip route show default
default via 192.168.1.1 dev wlan0 proto dhcp metric 600

Значення: Інтернет‑трафік залишається на wlan0. Це і є суть роздільного тунелю.

Рішення: Якщо дефолтний маршрут вказує на wg0, з’ясуйте, чи справді ви хотіли повний тунель і чи є винятки для локальної LAN.

Завдання 4: Перевірити, який маршрут вибере ядро для конкретного призначення

cr0x@server:~$ ip route get 10.40.12.34
10.40.12.34 dev wg0 src 10.99.0.2 uid 1000
    cache

Значення: Пакети до 10.40.12.34 підуть через wg0, з джерелом 10.99.0.2.

Рішення: Якщо він показує dev wlan0, ваш роздільний тунель не встановлено або маршрут перекрито більш специфічним записом.

Завдання 5: Перевірити конфігурацію DNS на системах з systemd-resolved

cr0x@server:~$ resolvectl status wg0
Link 8 (wg0)
    Current Scopes: DNS
         Protocols: +DefaultRoute
Current DNS Server: 10.40.0.53
       DNS Servers: 10.40.0.53

Значення: Для wg0 призначено DNS‑сервер. Залежно від налаштування, він може стати дефолтним для всіх запитів.

Рішення: Якщо внутрішні імена не резолвляться при правильних маршрутах, налаштуйте split DNS (routing domains) замість примусової переадресації всього DNS через корп.

Завдання 6: Підтвердити, що внутрішнє резолвування імен працює як очікується

cr0x@server:~$ resolvectl query jira.corp
jira.corp: 10.40.12.80                  -- link: wg0

-- Information acquired via protocol DNS in 22.4ms.
-- Data is authenticated: no

Значення: Запит оброблено через DNS на wg0 і повернув внутрішню IP.

Рішення: Якщо воно резолвиться через wlan0 на публічну IP або дає NXDOMAIN — у вас проблема з DNS‑маршрутизацією, а не з WireGuard.

Завдання 7: Доведіть маршрут за допомогою targeted curl з прив’язкою до інтерфейсу

cr0x@server:~$ curl -sS --interface wg0 -o /dev/null -w "HTTP %{http_code}\n" http://10.40.12.80/
HTTP 200

Значення: Сервіс доступний через wg0 і відповідає. Проблема додатка, ймовірно, у виборі імені DNS, проксі або аутентифікації.

Рішення: Якщо прив’язка до wg0 не вдається, а без прив’язки працює (або навпаки), ви виявили асиметрію маршрутів або поведінку локального проксі.

Завдання 8: Перевірити MTU (тихий вбивця «працює для малого трафіку»)

cr0x@server:~$ ping -M do -s 1420 -c 3 10.40.12.80
PING 10.40.12.80 (10.40.12.80) 1420(1448) bytes of data.
1428 bytes from 10.40.12.80: icmp_seq=1 ttl=63 time=38.2 ms
1428 bytes from 10.40.12.80: icmp_seq=2 ttl=63 time=38.6 ms
1428 bytes from 10.40.12.80: icmp_seq=3 ttl=38.1 ms

--- 10.40.12.80 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms

Значення: 1420‑байтовий payload з DF встановленим працює. MTU, ймовірно, не ваша проблема при такому розмірі.

Рішення: Якщо ви бачите «Frag needed», зменшіть MTU інтерфейсу WireGuard (звичні значення: 1280–1420) і протестуйте знову.

Завдання 9: Переглянути MTU інтерфейсу і лічильники

cr0x@server:~$ ip -s link show dev wg0
8: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/none
    RX:  bytes packets errors dropped  missed   mcast
    98123456  74231      0       12       0       0
    TX:  bytes packets errors dropped carrier collsns
    13200456  52122      0        3       0       0

Значення: Є деякі дропи. Невелика кількість дропів може бути нормою; стійке зростання під навантаженням може свідчити про MTU, чергування або проблеми з фаєрволом.

Рішення: Якщо дропи швидко ростуть під час передачі, протестуйте зі зниженням MTU і перевірте фільтрацію UDP.

Завдання 10: Підтвердити IP‑форвардинг і NAT на шлюзі (site‑to‑site або road‑warrior через сервер)

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

Значення: Сервер може маршрутувати між інтерфейсами.

Рішення: Якщо значення 0, клієнти можуть встановлювати handshake, але не дістатися до внутрішніх мереж за сервером. Увімкніть форвардинг і зробіть це персистентним.

Завдання 11: Перевірити правила NAT/forward (приклад iptables)

cr0x@server:~$ sudo iptables -t nat -S | grep -E "POSTROUTING|wg0"
-A POSTROUTING -s 10.99.0.0/24 -o eth0 -j MASQUERADE

Значення: VPN‑клієнти (10.99.0.0/24) NATляться при виході через eth0. Це звично для road‑warrior доступу до приватних мереж.

Рішення: Якщо ви очікуєте маршрутизований (без NAT) режим, приберіть MASQUERADE і переконайтесь, що внутрішні маршрутизатори знають, як дістатися до VPN підмережі.

Завдання 12: Подивитися, чи використовується політична маршрутизація або мітки (просунутий Linux 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

Значення: Трафік, позначений 0xca6c, використовує таблицю маршрутизації 51820 (звично для поведінки wg-quick в деяких налаштуваннях).

Рішення: Якщо лише деякі додатки мають використовувати тунель, міткуйте ці потоки цілеспрямовано (cgroups, iptables mangle) і залишайте решту без міток.

Завдання 13: Перевірити AllowedIPs та endpoints у peer на клієнті

cr0x@server:~$ sudo wg show wg0 peers
Hx2e1F0rQyQH7cQqX2o3v9KQ0m7E4uE3r4Y8z8u4L0w=
cr0x@server:~$ sudo wg show wg0 peer Hx2e1F0rQyQH7cQqX2o3v9KQ0m7E4uE3r4Y8z8u4L0w=
peer: Hx2e1F0rQyQH7cQqX2o3v9KQ0m7E4uE3r4Y8z8u4L0w=
  endpoint: 198.51.100.22:51820
  allowed ips: 10.40.0.0/16, 172.20.10.5/32
  latest handshake: 1 minute, 10 seconds ago
  transfer: 12.04 MiB received, 88.31 MiB sent

Значення: Ваші роздільні префікси присутні. Endpoint відомий і handshake живий.

Рішення: Якщо AllowedIPs містить широкий діапазон, якого ви не планували, виправте конфіг перш ніж продовжувати. Більш глибоке налагодження інших проблем — марна трата часу.

Завдання 14: Вловити витоки та трафік, що йде не туди, за допомогою tcpdump (швидка правда)

cr0x@server:~$ sudo tcpdump -ni wg0 host 10.40.12.80 and port 443 -c 3
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
IP 10.99.0.2.54422 > 10.40.12.80.443: Flags [S], seq 18273612, win 64240, options [mss 1360,sackOK,TS val 102030 ecr 0,nop,wscale 7], length 0
IP 10.40.12.80.443 > 10.99.0.2.54422: Flags [S.], seq 23011222, ack 18273613, win 65160, options [mss 1360,sackOK,TS val 556677 ecr 102030,nop,wscale 7], length 0
IP 10.99.0.2.54422 > 10.40.12.80.443: Flags [.], ack 1, win 502, options [nop,nop,TS val 102031 ecr 556677], length 0
3 packets captured

Значення: TCP‑handshake відбувається через wg0. Маршрутизація для цього потоку вірна.

Рішення: Якщо ви не бачите пакетів на wg0, але очікуєте їх — перевірте ip route get і правила політичної маршрутизації.

Завдання 15: Виявити, коли підлягаюча мережа блокує UDP (симптом: handshake не відбувається)

cr0x@server:~$ sudo tcpdump -ni eth0 udp port 51820 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 203.0.113.50.53211 > 198.51.100.22.51820: UDP, length 148
IP 203.0.113.50.53211 > 198.51.100.22.51820: UDP, length 148
IP 203.0.113.50.53211 > 198.51.100.22.51820: UDP, length 148
5 packets captured

Значення: Пакети доходять до сервера. Якщо handshakes все одно не відбуваються, сервер може відкидати відповіді або ключі не співпадають.

Рішення: Якщо ви нічого не бачите, мережа може блокувати UDP або endpoint/порт неправильні. Вирішіть доступність перш ніж торкатись маршрутизації.

Завдання 16: Підтвердити, що зворотна маршрутна перевірка не відкидає відповіді (Linux rp_filter)

cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter
net.ipv4.conf.all.rp_filter = 1

Значення: Досить строгий reverse path filtering може відкидати асиметричний трафік (поширене при змішуванні VPN і кількох канальних uplink).

Рішення: Якщо ви використовуєте просунуту політичну маршрутизацію, розгляньте встановлення rp_filter у слабшому режимі (2) на відповідних інтерфейсах після розуміння компромісів безпеки.

Швидкий план діагностики

Коли роздільний тунель «ніби працює», ваш час з’їдає невірний рівень. Ось порядок, що зазвичай знаходить вузьке місце найшвидше.
Він орієнтований на продакшн‑реальність: більшість збоїв — це дрейф конфігурацій, несподіванки маршрутизації, DNS або MTU — не криптографія.

По‑перше: чи тунель живий?

  • Перевірка: wg show на обох кінцях.
  • Сигнал: Свіжий handshake + зростаючі лічильники передачі.
  • Якщо погано: перевірте доступність endpoint, правила фаєрволу, UDP‑шлях, правильність ключів і час (розбіжність годин зазвичай не фатальна тут, але не запускайте старий NTP).

По‑друге: чи маршрутизація робить те, що ви думаєте?

  • Перевірка: ip route і ip route get <target>.
  • Сигнал: Потрібні вам призначення йдуть через wg0; дефолтний маршрут залишається локальним.
  • Якщо погано: виправте AllowedIPs спочатку; потім розгляньте політичні правила маршрутизації або конфліктні маршрути від NetworkManager/VPN клієнтів.

По‑третє: чи DNS слідує розділенню?

  • Перевірка: resolvectl query для внутрішніх імен і який лінк відповів.
  • Сигнал: Внутрішні зони резолвляться через DNS на wg0 або за правилами split DNS; публічні імена резолвляться локально як заплановано.
  • Якщо погано: реалізуйте split DNS (routing domains) або запустіть локальний stub‑резолвер і форвардьте внутрішні зони.

По‑четверте: чи MTU робить великі передачі нестабільними?

  • Перевірка: DF pings на 1280/1380/1420 і порівняйте «мале працює, велике зависає».
  • Сигнал: Немає помилок «fragmentation needed»; стабільна пропускна здатність.
  • Якщо погано: зменшіть MTU для wg0; перевірте path MTU на підлягаючому шарі; шукайте PPPoE або капшн‑накладення.

По‑п’яте: чи фаєрволи та NAT‑правила узгоджені з вашою історією?

  • Перевірка: форвардинг, NAT (якщо використовується), і що внутрішні маршрутизатори знають зворотні шляхи (якщо не NAT‑ите).
  • Сигнал: зворотній трафік доходить до клієнтів; нема асиметричних відкидань rp_filter.
  • Якщо погано: або NAT‑іть навмисно, або додайте правильні маршрути в внутрішній мережі; не робіть напівзаходів.

Три корпоративні міні‑історії з передової

1) Інцидент, спричинений хибним припущенням: «AllowedIPs — це лише ACL»

Середня за розміром компанія впровадила WireGuard замість застарілого віддаленого VPN. Пілотна група була в основному розробниками,
і все йшло добре — поки не приєдналася фінансова команда разом з кількома сторонніми SaaS‑інтеграціями, що використовували фіксовані allowlists за IP.

Один інженер припустив, що AllowedIPs — це виключно «ACL» на peer — типу «що клієнт має право досягати».
Вони додали 0.0.0.0/0 на клієнті, бо «це безпечно; ми ж NATимо корпоративні підмережі».
Результат — випадковий повний тунель: увесь вихідний інтернет‑трафік почав іти через корпоративний egress.

Це не вийшло гучно. Це вийшло соціально: затримки до звичних сайтів зросли, перевірки геолокації почали флагувати логіни,
а внутрішня IDS побачила патерни трафіку, для яких її не підготували. Веб‑система обліку фінансів почала лімітувати запити,
бо вони тепер йшли з обмеженого числа спільних NAT‑IP.

Технічна діагностика була проста: дефолтний маршрут вказував на wg0, а DNS було змінено на внутрішні резолвери.
«VPN повільний» — скарга була реальна, але корінь проблеми не в продуктивності WireGuard — а в ненавмисній зміні архітектури.
Виправлення було нудним: прибрати 0.0.0.0/0, маршрутувати лише корпоративні префікси і залишити SaaS‑трафік локальним.

Тривалий висновок: в WireGuard AllowedIPs — це маршрутизація. Ставтесь до цього як до редагування таблиці маршрутів на кожному ноутбуці — бо так воно і є.

2) Оптимізація, що відкотилась: «Зменшимо MTU заради швидкості»

Інша організація мала глобальний штат і WireGuard‑шлюз в одному регіоні. Вони помітили нестабільні завантаження файлів в внутрішнє сховище артефактів.
Хтось згадав «проблеми з MTU» з давнього VPN і вирішив «оптимізувати», агресивно зменшивши MTU до 1200 на всіх клієнтах.
Аргумент: менші пакети, менше фрагментації, менше ретранів. Звучало правдоподібно на нараді.

Насправді сталося таке: інтерактивний трафік трохи стабілізувався, але пропускна здатність для великих передач впала катастрофічно, особливо на лінках з великою затримкою.
Використання CPU на клієнтах і шлюзі зросло через більшу кількість пакетів на мегабайт. Деякі endpoint‑и стикнулися з лімітами за кількістю пакетів або падіннями черг.
Сховище артефактів не просто відчуло уповільнення — великі публікації почали таймаутитись.

Складність у тому, що «воно працює» залишалося правдою для малих тестів: можна було curl невеликий endpoint, ping працював, SSH відчувався нормально.
Біль pain виявився лише під час великих потоків даних.

Виправлення: перестати гадати. Вони провели DF pings, щоб знайти MTU, який працює енд‑ту‑енд (часто 1380–1420 залежно від підлягаючого каналу),
встановили розумний MTU і зменшили кількість ретраїв завантажень, покращивши таймаути замість штучного зменшення пакетів.
Ця «оптимізація» стала лише прикладом cargo‑cult‑налаштування в постмортемі.

3) Нудна, але правильна практика, що врятувала ситуацію: «Ми ведемо інвентар маршрутів»

Регульована організація з кількома дочірніми компаніями тримала WireGuard‑шар доступу до декількох внутрішніх підмереж.
Їхня мережа була латана: перекриваючі RFC1918 діапазони, злиття бізнесів і кілька «тимчасових» NATів, що пережили декілька менеджерів.
Це було місце, де «просто маршрутуй 10/8» — рішення для кар’єри.

Операційна команда вела простий інвентар маршрутів: які внутрішні префікси існують, хто їх власник, які доступні через VPN,
і які ніколи не повинні маршрутизуватись через віддалений доступ через класифікацію даних.
Це не було гламурно. Зберігалось у системі керування версіями. Рецензувалось як код.

Коли новий бізнес‑підрозділ попросив доступ, команда додала два конкретні /24 до AllowedIPs і оновила DNS‑routing domains.
Через два тижні інша команда випадково ввела перекриваючу підмережу в лабораторії, яка б викрала трафік, якби використовували широкі префікси.
Оскільки VPN‑маршрути були вузькими й задокументованими, нічого не витекло і нічого не зламалося.

Інцидент, який міг статись, не стався. Найкращі операційні перемоги часто невидимі і глибоко неелегантні.
І команда нормально спала, що теж важливий SRE‑показник.

Поширені помилки: симптоми → корінь проблеми → виправлення

1) Симптом: Інтернет‑трафік несподівано йде через VPN

Корінь проблеми: На клієнті в AllowedIPs включено 0.0.0.0/0 і/або ::/0, що встановлює дефолтний маршрут через wg0.

Виправлення: Замініть на конкретні префікси. Якщо ви хочете «майже повний тунель», додайте явні винятки для локальної LAN і перевірте зворотні шляхи.

2) Симптом: «Handshake працює, але я не можу дістатися внутрішніх сервісів»

Корінь проблеми: Сервер не форвардить пакети (ip_forward=0), або внутрішня мережа не має маршрутів назад до VPN‑підмережі.

Виправлення: Увімкніть форвардинг і або NAT на шлюзі, або додайте правильні маршрути на внутрішніх маршрутизаторах. Виберіть один підхід і дотримуйтесь його.

3) Симптом: Внутрішні імена не резолвляться, але IP‑адреси працюють

Корінь проблеми: DNS все ще вказує на локальні резолвери; внутрішні зони не форвардяться через VPN.

Виправлення: Налаштуйте split DNS (per‑interface routing domains) або встановіть VPN DNS при підключенні. Перевірте за допомогою resolvectl query.

4) Симптом: Деякі внутрішні сайти завантажуються, інші зависають на вході або під час великих завантажень

Корінь проблеми: MTU/PMTUD проблеми, часто через інкапсуляцію підлягаючого шару або блоковані ICMP «fragmentation needed» повідомлення.

Виправлення: Зменшіть MTU для wg0; тестуйте DF pings; якщо ви контролюєте фаєрволи, дозвольте потрібні типи ICMP.

5) Симптом: Локальні LAN‑пристрої перестають працювати, коли VPN підключений

Корінь проблеми: Повний тунель без винятків для LAN, або зміни DNS, що призводять до іншого резолвингу локальних імен, або rp_filter відкидає пакети на багатодоменних системах.

Виправлення: Тримайте роздільний тунель вузьким; додайте явні маршрути для LAN через місцевий шлюз за потреби; розгляньте слабший rp_filter у просунутих сценаріях маршрутизації.

6) Симптом: Два peer «змагаються» і трафік йде не туди

Корінь проблеми: Перекриваючі AllowedIPs між peer. Правило найдовшого префікса вибирає peer, якого ви не мали на увазі, або маршрути змінюються при зміні конфігів.

Виправлення: Зробіть AllowedIPs неперекриваючими; якщо потрібно перекривання — використайте більш специфічні префікси навмисно і документуйте власність.

7) Симптом: VPN працює на домашньому Wi‑Fi, але не в готелі/аеропорту

Корінь проблеми: UDP блокується або captive portal заважає; endpoint недоступний, поки портал не буде прийнятий.

Виправлення: Збережіть не‑VPN шлях для доступу до порталу; розгляньте fallback‑порт або альтернативну стратегію транспорту на вашому шлюзі; налагоджуйте за допомогою tcpdump на сервері.

Жарт #2 (коротко, по темі): Captive portal — єдина система, що може одночасно зламати і мережу, і оптимізм однією і тією ж сторінкою.

Контрольні списки / покроковий план

План 1: Побудувати чистий роздільний тунель для «лише корпоративних підмереж»

  1. Зробіть інвентар того, що вам реально потрібно.
    Перелічіть внутрішні префікси і внутрішні DNS‑зони. Якщо ви не можете їх перелічити — ви не готові робити це безпечно.
  2. Призначте стабільні VPN‑адреси клієнтам.
    Віддавайте перевагу /32 на клієнт (IPv4) і /128 на клієнт (IPv6), щоб маршрути були однозначні.
  3. Клієнтська конфіг: тримайте AllowedIPs вузькими.
    Включайте лише внутрішні підмережі сервісів і/або конкретні /32.
  4. Серверна конфіг: приймайте лише VPN‑IP(и) клієнта.
    У секції peer сервера використовуйте VPN /32 клієнта. Не приймайте широкі діапазони, якщо це не site‑to‑site.
  5. Маршрутизація на сервері: вирішіть між NAT або маршрутизованими відповідями.

    • Якщо NAT: MASQUERADE підмережі VPN на інтерфейс внутрішньої мережі.
    • Якщо маршрутизовано: рекламуйте VPN‑підмережу у внутрішню маршрутизовану доменну.
  6. DNS: вирішіть між «весь DNS через VPN» і split DNS.
    Якщо користувачам потрібен незайманий локальний браузинг, імплементуйте split DNS. Інакше у вас буде нескінченна черга заявок «VPN ламає портал принтера».
  7. MTU: встановіть розумні значення і протестуйте.
    Почніть з 1420. Якщо у вас PPPoE або вкладені тунелі, очікуйте зменшувати значення.
  8. Логування та моніторинг.
    Слідкуйте за часами handshake, лічильниками передачі та дропами інтерфейсу під час катання.

План 2: Політична маршрутизація (просунуто, варта зусиль для спільних хостів)

  1. Створіть wg0 без встановлення широких маршрутів. Використайте вузькі AllowedIPs або ручне управління маршрутами.
  2. Створіть окрему таблицю маршрутизації для VPN‑трафіку. Наприклад: table 51820.
  3. Додайте маршрути до таблиці 51820 для корпоративних префіксів через wg0.
  4. Позначте трафік, що має йти через VPN. Використайте iptables/nftables mangle або маркування на основі cgroup.
  5. Додайте ip rules, що маплять fwmark на VPN‑таблицю.
  6. Тестуйте за допомогою ip route get і tcpdump. Не «припускайте», що ви промаркували те, що думаєте.
  7. Документуйте політику. Через шість місяців ви забудете, чому частина трафіку обходить тунель, і майбутнє‑ви буде сердитим.

План 3: «Майже повний тунель, але з локальним LAN» (робіть це обережно)

  1. Використовуйте повний тунель AllowedIPs (0.0.0.0/0, ::/0) лише якщо ви дійсно цього хочете.
  2. Додайте явні маршрути для локальних підмереж (наприклад 192.168.0.0/16 або вашу реальну LAN) через місцевий шлюз.
  3. Перевірте зворотні шляхи. Деякі локальні пристрої не відповідатимуть на вашу VPN‑source IP; можливо, доведеться NAT‑ити LAN‑трафік або обрати правильне джерело пакетів.
  4. Тестуйте друк, кастинг і локальне виявлення. Мультікаст/броадкаст виявлення часто не пройде через VPN; керуйте очікуваннями.

FAQ

1) Чи є роздільний тунель «менш безпечним», ніж повний тунель?

Це залежить від вашої моделі загроз. Роздільний тунель тримає некорпоративний трафік поза VPN, зменшуючи навантаження і площу ураження.
Але це також означає, що клієнт одночасно в публічній мережі і в корпоративній. Якщо вам потрібен суворий контроль виходу, DLP або послідовна інспекція — повний тунель може бути виправданим, але робіть це свідомо.

2) Що саме робить AllowedIPs на клієнті?

Це селектор маршрутизації: призначення, що відповідають AllowedIPs, йдуть у WireGuard‑тунель до відповідного peer.
Це також фільтр, які адреси джерела прийнятні від цього peer. Це не «лише ACL».

3) Чому тунель підключається, але я не можу дістатися нічого за сервером?

Зазвичай проблема у форвардингу або зворотній маршрутизації. Handshake доводить ключі і досяжність endpoint, але не те, що внутрішня мережа знає, як повернути пакети.
Перевірте net.ipv4.ip_forward, правила NAT (якщо NAT використовується) або внутрішні маршрути назад до VPN‑підмережі.

4) Як тримати інтернет‑трафік локальним, але використовувати внутрішній DNS?

Використовуйте split DNS: маршрутуйте лише внутрішні зони до VPN‑резолвера і залишайте все інше на локальному резолвері.
На systemd‑resolved це робиться за допомогою per‑link DNS‑серверів і routing domains.

5) Чи можу я розділяти тунель за додатком (тільки мій браузер через VPN)?

Не нативно лише за допомогою WireGuard. Це робиться засобами ОС: політичною маршрутизацією, маркуванням пакетів і іноді per‑app VPN на мобільних платформах.
На Linux поєднуйте ip rule з fwmarks і маршрутами в кастомній таблиці.

6) Чому деякі корпоративні додатки ламаються лише при підключеному VPN?

Типові причини: зміни DNS (split‑horizon), поведінка proxy auto‑config, або перекриття маршрутів (ваш VPN‑маршрут захоплює підмережу, що використовується локально).
Перевірте за допомогою ip route get до endpoint додатка і подивіться, який лінк відповів на DNS‑запит.

7) Чи потрібен PersistentKeepalive для роздільного тунелю?

Якщо клієнт за NAT (часто) — так, зазвичай. Keepalive допомагає підтримувати NAT‑мапінг, щоб вхідні пакети зі сторони сервера могли дістатися клієнта.
Для завжди‑включених site‑to‑site з стабільними endpoints ви можете не потребувати його. Для ноутбуків у кав’ярнях — воно потрібне.

8) Чи варто маршрутизувати всі RFC1918 діапазони через VPN?

Уникайте цього, якщо ви дійсно не контролюєте їх всі. Маршрутизація 10.0.0.0/8 через VPN часто конфліктує з домашніми мережами, хмарними VPC і лабораторними середовищами.
Маршрутуйте лише те, що ви власне маєте і що вам потрібно. Будьте конкретними; ваше майбутнє «я» скаже вам дякую.

9) Як налагоджувати «пінг працює, а HTTPS ні»?

Почніть з MTU і фаєрволу. ICMP може пройти, а TCP застопоритись через проблеми фрагментації. Тестуйте DF pings і аналізуйте tcpdump.
Також перевірте, що IP сервісу, до якого ви звертаєтесь, дійсно доступний і не змінюється через DNS.

Висновок: наступні кроки, що не зруйнують вам тиждень

Роздільний тунель з WireGuard простий в концепції і дивно легкий для помилок у продакшні, переважно тому, що люди оптимістично ставляться до маршрутизації.
Переможна стратегія — не хитрощі. Це ясність: вузькі префікси, явна поведінка DNS і перевірка за допомогою реальних інструментів.

Практичні наступні кроки:

  1. Визначте мету маршрутизації в одному реченні («лише ці підмережі через VPN» або «усе через VPN, крім LAN»). Запишіть це.
  2. Аудит AllowedIPs у кожному клієнтському профілі. Приберіть широкі діапазони без обґрунтування.
  3. Перевірте двома командами: wg show (alive) і ip route get (шлях правди).
  4. Налаштуйте DNS свідомо: або прийміть «весь DNS через VPN», або впровадьте split DNS; не допускайте дрейфу.
  5. Протестуйте MTU один раз на репрезентативних мережах і встановіть розумне значення; не «оптимізуйте» навмання.
  6. Документуйте префікси так, як ви б документували фаєрвол‑правила. Бо це — правила фаєрволу з кращим PR.
← Попередня
ZFS zpool import -d: пошук пулів при зміні шляхів пристроїв
Наступна →
Як читати CPU-бенчмарки, щоб вас не обвели

Залишити коментар