WireGuard VPN: Налаштуйте власний сервер без зайвого відкриття портів

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

Ви хочете VPN, бо ваш ноутбук пересувається між Wi‑Fi у кавʼярнях, готелях і тим загадковим «FREE_AIRPORT_WIFI». Ви також хочете хостити власне рішення, бо прочитали достатньо звітів про злами, щоб зрозуміти: «довірся нам» — це не модель безпеки.

Пастка: люди трактують «налаштувати VPN» як «відкрити купу портів і сподіватися». Саме так ви отримуєте досяжний сервер — і для атакуючих, сканерів і вашого майбутнього себе о 3 ранку, який дивується, чому маршрути не працюють. Ми зробимо це нудно, але правильно: один відкритий UDP‑порт (або жодного, якщо використовується тільки вихідний шлях), строгий брандмауер, явна маршрутизація і план діагностики, що не базується на відчуттях.

Позиція безпеки: «один порт — одна задача»

WireGuard — це не набір демонів і плагінів. Це невеликий протокол і компактна реалізація. Ставтеся до нього як до пристрою однієї функції:
відкрийте один UDP‑порт (якщо мусите), приймайте пакети тільки на цьому порту з будь‑якого джерела і довіряйте криптографічному рукостисканню WireGuard.

Ваш брандмауер не існує для того, щоб «зробити VPN безпечним». Брандмауер покликаний запобігти випадковому відкриттю всього іншого, поки ви намагаєтеся бути хитромудрим. Не будьте хитрими.

Як зазвичай виглядають «зайві діри»

  • Відкрити SSH для всіх «лише на час», а потім забути на рік.
  • Перекидати випадкові порти, бо якийсь блог так порадив, хоча WireGuard потребує одного UDP‑порту.
  • Дозволяти форвардинг з VPN‑інтерфейсу в LAN без політики, бо «це зашифровано».
  • Встановити веб‑інтерфейс під root, бо «так простіше керувати».

Шифрування — це не дозвіл. Це транспорт. Дозвіл — це маршрутизація і політика.

Цитата, бо вона досі актуальна

«Надія — це не стратегія.» — Джеймс Кемерон

Це не цитата з операційної практики, але підходить: не сподівайтеся, що ваш брандмауер в порядку; перевіряйте це.

Факти про WireGuard і контекст (те, що люди часто плутають)

Тут коротко спеціально. Сенс — налаштувати ментальну модель, щоб ви перестали дебажити неправильний рівень.

  1. WireGuard працює тільки через UDP за задумом. Якщо ви женетеся за «TCP‑повторами», ви дебагуєте не те.
  2. Використовує Noise‑базоване рукостискання (NoiseIK). Це одна з причин його швидкості та простоти у порівнянні зі старими VPN‑стеками.
  3. Потрапив у ядро Linux у 5.6 (2020). До того він був поза деревом; нині це стандарт для сучасних дистрибутивів.
  4. «Peers» — це не «користувачі». Peer — це ключова пара і політика маршрутизації; ідентичність живе в ключах, а не в іменах користувачів.
  5. AllowedIPs — це і маршрутизація, і контроль доступу. Вони визначають, які маршрути інсталюються і який трафік приймається від peer.
  6. Прохідність через NAT — це не магія; це keepalive. PersistentKeepalive — це по суті ваше чемне постукування кожні N секунд, щоб stateful‑файрволи не забували про вас.
  7. WireGuard не має renegotiation як IPsec. Ключі можуть оновлюватися, але модель навмисно мінімалістична.
  8. Уникає розпорошення алгоритмів. Крипто‑вибір обмежений; вам не дають «вибирати все підряд», і це функція, а не баг.

Жарт №1: VPN, що «підтримує всі шифри», — це як ресторан з 40‑сторінковим меню: ніхто не перевіряє свіжість.

Виберіть топологію: VPS‑хаб, домашній хаб або «без вхідних портів»

Найчистіший спосіб уникнути зайвих дір — вирішити, з чим ви намагаєтеся зʼєднатися. Є три поширені патерни, і вони не взаємозамінні.

Топологія A: VPS як хаб (рекомендовано для більшості)

Ви орендуєте невеликий VPS, відкриваєте один UDP‑порт (наприклад, 51820/udp) і підключаєте до нього клієнтів. Якщо потрібен доступ до домашніх пристроїв, ви також запускаєте peer вдома, який ініціює підключення до VPS і оголошує маршрути домашньої мережі.

Чому це добре:

  • Не треба виставляти ваш домашній IP або пробивати дири в ненадійному роутері провайдера.
  • Отримуєте стабільну публічну кінцеву точку і передбачувані правила брандмауера.
  • Можете тримати SSH закритим для загалу і доступним тільки для мережі управління або бастіону.

Топологія B: Домашній сервер як хаб (працює, але ви відповідаєте за роутер)

Ви пробросите один UDP‑порт з домашнього роутера на ваш WireGuard‑сервер. Це нормально, поки нормально. Але це також один апдейт прошивки від «чому роутер скинув усі правила».

Роби це тільки якщо розумієте поведінку stateful‑брандмауера вашого роутера і готові терпіти випадкові відмови.

Топологія C: «Без вхідних портів»: тільки вихідні підключення з рандеву

Якщо середовище забороняє вхідні порти (корпоративні мережі, CGNAT, ворожі ISP), ви все одно можете зробити робочу систему. Зазвичай підхід такий:

  • Публічний VPS запускає WireGuard‑сервер (один відкритий UDP‑порт на VPS).
  • Усе інше (домашній шлюз, ноутбуки) ініціює вихідні підключення до цього VPS.

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

Заходи жорсткого захисту, які справді важливі

1) Розмістіть точку входу WireGuard на мінімальному хості

Не співхостіть endpoint VPN з вашим улюбленим Kubernetes‑кластером, сімейною фотогалереєю та експериментальним Node‑додатком. Кожна додаткова служба множить blast radius. Якщо вам потрібен швейцарський ніж, гаразд. Але не дивуйтеся, коли поріжетесь.

2) Обмежте SSH так, ніби ви серйозно

SSH зазвичай — справжня «зайва діра». Якщо сервер доступний з публічного інтернету, за умовчанням робіть так:

  • Тільки SSH‑ключі, без парольної аутентифікації.
  • Фаєрвол SSH до довіреного діапазону IP (офіс, дім або ваша VPN‑підмережа).
  • Розгляньте окремий інтерфейс управління або бастіон, якщо це для команди.

3) Політика брандмауера: дозволити WireGuard, дозволити established, скидати решту

Базовий набір правил нудний, але достатній:

  • Inbound: дозволити UDP 51820 (або ваш порт) до хоста WireGuard.
  • Inbound: дозволити SSH тільки з обмежених джерел.
  • Forwarding: дозволяти тільки те, що ви дійсно маєте намір пропускати з wg0 на інші інтерфейси.

VPN‑інтерфейс — не перепустка в вашу LAN. Це мережевий сегмент. Ставтеся до нього відповідно.

4) Політика маршрутизації — це ваш контроль доступу

WireGuard не робить «користувацькі дозволи» як корпоративні концентратори VPN. Ваші органи керування:

  • AllowedIPs для кожного peer (які маршрути peer може відправляти і отримувати).
  • Правила брандмауера на wg0 (який трафік дозволено після надходження).
  • IP‑форвардинг / рішення з NAT (що сервер маршрутизує далі).

5) MTU: мовчазний вбивця

WireGuard швидкий. Але він легко може втопити вашу пропускну здатність, якщо ви інкапсулюєте всередині PPPoE, VLAN або інших тунелів і не підлаштували MTU. Коли сумніваєтесь — почніть з 1420 на wg0 і вимірюйте.

6) Логування: достатньо для діагностики, але не для витоку

WireGuard свідомо тихий. Це добре. Але вам потрібна системна спостережуваність:

  • Лічильники інтерфейсу й таблиці маршрутів.
  • Лічильники пакетів у брандмауері.
  • Журнали ядра про відкинуті пакети (обережно).

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

Контрольний список: перед тим як торкатися сервера

  • Визначте підмережу VPN (наприклад: 10.6.0.0/24). Не використовуйте знову LAN‑підмережу.
  • Визначте, для кожного клієнта split tunnel чи full tunnel. За замовчуванням — split tunnel, якщо вам не потрібен весь трафік через VPN.
  • Виберіть порт endpoint (за замовчуванням 51820/udp підходить). Безпека через невідкритість порту — не план, але зменшення шуму — ок.
  • Запишіть приватні підмережі, до яких хочете доступ (наприклад: 192.168.50.0/24 у домівці).
  • Вирішіть, чи сервер має робити NAT для трафіку клієнтів (full tunnel) або тільки маршрутизувати до внутрішніх мереж.

Покроково: VPS‑хаб на Ubuntu з nftables

Цей потік припускає:

  • Публічний інтерфейс сервера: eth0
  • Інтерфейс WireGuard: wg0
  • VPN‑підмережа: 10.6.0.0/24
  • VPN‑IP сервера: 10.6.0.1
  • VPN‑IP клієнта: 10.6.0.2

Контрольний список: чого ви маєте досягти

  • Тільки UDP 51820 вхідний відкритий (плюс щільно обмежений SSH, якщо потрібно).
  • wg0 піднімається на старті, конфігурація належить root, дозволи локовані.
  • IP‑форвардинг ввімкнено тільки якщо ви реально маршрутизуєте між інтерфейсами.
  • Правила брандмауера явно дозволяють тільки потрібний трафік і нічого зайвого.
  • Клієнтські конфігурації відповідають AllowedIPs, endpoint і вибору DNS.

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

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

Завдання 1: підтвердити підтримку WireGuard і базові дані ОС

cr0x@server:~$ uname -r
6.5.0-41-generic

Що це означає: Сучасне ядро; вбудована підтримка WireGuard доступна.
Рішення: Використовуйте wireguard-tools і модуль ядра; уникайте userspace‑шимів, якщо у вас немає дивного платформного обмеження.

Завдання 2: встановити інструменти WireGuard

cr0x@server:~$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done
cr0x@server:~$ sudo apt-get install -y wireguard wireguard-tools nftables
Reading package lists... Done
Setting up wireguard-tools (1.0.20210914-1ubuntu2) ...
Setting up wireguard (1.0.20210914-1ubuntu2) ...
Setting up nftables (1.0.2-1ubuntu1) ...

Що це означає: Інструменти присутні. Рішення: Продовжуйте з systemd‑керованим інтерфейсом і правилами nftables. Якщо ваш дистрибутив за замовчуванням використовує ufw, вирішіть зараз, чи будете ви з ним працювати, чи відключите; змішувати фаєрволи — це хобі, а не карʼєра.

Завдання 3: згенерувати ключі сервера з правильними дозволами

cr0x@server:~$ umask 077
cr0x@server:~$ sudo mkdir -p /etc/wireguard
cr0x@server:~$ sudo bash -c 'wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub'
cr0x@server:~$ sudo ls -l /etc/wireguard
total 8
-rw------- 1 root root 45 Oct 12 10:20 server.key
-rw------- 1 root root 45 Oct 12 10:20 server.pub

Що це означає: Ключі існують і не доступні для всіх.
Рішення: Якщо дозволи ширші за 600, виправте; не продовжуйте з халатною обробкою ключів.

Завдання 4: написати конфіг інтерфейсу сервера

cr0x@server:~$ sudo bash -c 'cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.6.0.1/24
ListenPort = 51820
PrivateKey = '"$(sudo cat /etc/wireguard/server.key)"'
SaveConfig = false

# If you will route to other networks, enable forwarding and add firewall rules (below).
EOF'
cr0x@server:~$ sudo chmod 600 /etc/wireguard/wg0.conf

Що це означає: Сервер налаштовано з внутрішньою адресою і UDP‑портом.
Рішення: Тримайте SaveConfig=false, якщо не хочете, щоб runtime‑зміни автоматично записувалися. Автозапис зручний, поки ним не стане незручно.

Завдання 5: підняти інтерфейс і перевірити його наявність

cr0x@server:~$ sudo systemctl enable --now wg-quick@wg0
Created symlink /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service → /lib/systemd/system/wg-quick@.service.
cr0x@server:~$ ip a show wg0
6: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 10.6.0.1/24 scope global wg0
       valid_lft forever preferred_lft forever

Що це означає: Інтерфейс піднятий з MTU 1420 (за замовчуванням wg‑quick).
Рішення: Якщо вашому середовищу потрібен інший MTU (поширено при PPPoE), виставте його явно зараз, а не ганяйтеся за фантомами пізніше.

Завдання 6: підтвердити, що сервер слухає на вибраному UDP‑порті

cr0x@server:~$ sudo ss -lunp | grep 51820
UNCONN 0      0           0.0.0.0:51820       0.0.0.0:*    users:(("wireguard",pid=1123,fd=6))

Що це означає: UDP‑сокет відкритий і привʼязаний.
Рішення: Якщо не слухає, зупиніться і подивіться journalctl на предмет помилок wg‑quick перш ніж торкатися правил брандмауера.

Завдання 7: налаштувати nftables, щоб дозволяти лише необхідне

cr0x@server:~$ sudo bash -c 'cat > /etc/nftables.conf <<EOF
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0;
    policy drop;

    ct state established,related accept
    iif "lo" accept

    # Allow WireGuard
    udp dport 51820 accept

    # Allow SSH only from a trusted source (example: your office IP)
    ip saddr 203.0.113.10 tcp dport 22 accept

    # Optional: allow ICMP for debugging (rate-limit in real environments)
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept

    counter reject with icmpx type port-unreachable
  }

  chain forward {
    type filter hook forward priority 0;
    policy drop;

    ct state established,related accept
    # Allow VPN clients to reach the server itself is handled in input;
    # forward is for routed traffic to other interfaces.

    # Example: allow VPN clients to reach a private LAN behind this server
    # iif "wg0" oif "eth0" ip daddr 192.168.50.0/24 accept
    # iif "eth0" oif "wg0" ip saddr 192.168.50.0/24 accept
  }

  chain output {
    type filter hook output priority 0;
    policy accept;
  }
}
EOF'
cr0x@server:~$ sudo systemctl enable --now nftables
cr0x@server:~$ sudo nft list ruleset | sed -n '1,60p'
table inet filter {
	chain input {
		type filter hook input priority filter; policy drop;
		ct state established,related accept
		iif "lo" accept
		udp dport 51820 accept
		ip saddr 203.0.113.10 tcp dport 22 accept
		ip protocol icmp accept
		ip6 nexthdr icmpv6 accept
		counter reject with icmpx type port-unreachable
	}

Що це означає: За замовчуванням drop, явні дозволи. Саме те, що потрібно для хоста, виставленого в інтернет.
Рішення: Якщо не можете обмежити SSH по джерелу, серйозно розгляньте переміщення SSH за VPN (тобто: жодного публічного SSH).

Завдання 8: перевірити, що ви випадково не виставили інші сервіси

cr0x@server:~$ sudo ss -lntup
Netid State  Recv-Q Send-Q Local Address:Port   Peer Address:Port Process
udp   UNCONN 0      0      0.0.0.0:51820       0.0.0.0:*     users:(("wireguard",pid=1123,fd=6))
tcp   LISTEN 0      4096   0.0.0.0:22          0.0.0.0:*     users:(("sshd",pid=904,fd=3))

Що це означає: Лише SSH і WireGuard слухають. Добре.
Рішення: Якщо бачите несподівані слушателі (веб‑дашборди, експортери, випадкові агенти), видаліть їх або закрийте фаєрволом. «Але він привʼязаний до 0.0.0.0» — не риса характеру.

Завдання 9: згенерувати пару ключів клієнта і додати peer

cr0x@server:~$ wg genkey | tee /tmp/client1.key | wg pubkey > /tmp/client1.pub
cr0x@server:~$ sudo wg set wg0 peer $(cat /tmp/client1.pub) allowed-ips 10.6.0.2/32
cr0x@server:~$ sudo wg show wg0
interface: wg0
  public key: 3rYlF8wF1aV9rS8dK0aJ7xw5w2Vn9pYqHc0Rr3X0u2M=
  private key: (hidden)
  listening port: 51820

peer: 7bTt2yqg3fJ0zq5fQm2v0QwqYk9mM9t8Gq2dZ1gk3jA=
  allowed ips: 10.6.0.2/32

Що це означає: Сервер тепер знає ключ peer і яку VPN‑IP йому призначено.
Рішення: Тримайте AllowedIPs обмеженими: /32 для кожного клієнта, якщо ви не робите site‑to‑site маршрутизацію. Широкі AllowedIPs викликають випадкові витоки маршрутів і конфлікти peer.

Завдання 10: створити конфіг клієнта (за замовчуванням — split tunnel)

cr0x@server:~$ SERVER_PUB=$(sudo cat /etc/wireguard/server.pub); echo "$SERVER_PUB"
3rYlF8wF1aV9rS8dK0aJ7xw5w2Vn9pYqHc0Rr3X0u2M=
cr0x@server:~$ cat > /tmp/client1.conf <<EOF
[Interface]
PrivateKey = $(cat /tmp/client1.key)
Address = 10.6.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = $(sudo cat /etc/wireguard/server.pub)
Endpoint = 198.51.100.25:51820
AllowedIPs = 10.6.0.0/24
PersistentKeepalive = 25
EOF

Що це означає: Split tunnel: клієнт направляє в тунель лише трафік для VPN‑підмережі.
Рішення: Почніть зі split tunnel. Увімкніть full tunnel тільки коли зможете чітко пояснити, навіщо він потрібен (і протестували поведінку DNS).

Завдання 11: перевірити handshake і лічильники трафіку на сервері

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

peer: 7bTt2yqg3fJ0zq5fQm2v0QwqYk9mM9t8Gq2dZ1gk3jA=
  allowed ips: 10.6.0.2/32
  latest handshake: 24 seconds ago
  transfer: 18.21 KiB received, 22.77 KiB sent

Що це означає: Рукостискання пройшло і трафік тече.
Рішення: Якщо «latest handshake» порожнє або дуже старе — дебагуйте досяжність (фаєрвол, endpoint, NAT) до того, як лізти в маршрути.

Завдання 12: перевірити таблицю маршрутів і політику на сервері

cr0x@server:~$ ip route show
default via 203.0.113.1 dev eth0 proto dhcp src 198.51.100.25 metric 100
10.6.0.0/24 dev wg0 proto kernel scope link src 10.6.0.1
203.0.113.0/24 dev eth0 proto kernel scope link src 198.51.100.25

Що це означає: Сервер знає, що VPN‑підмережа знаходиться на wg0.
Рішення: Якщо маршрут до 10.6.0.0/24 відсутній, wg0 налаштовано неправильно; не переходьте до «фіксів» NAT/mаршрутів, поки базовий інтерфейс не буде в порядку.

Завдання 13: ввімкнути IP‑форвардинг лише якщо ви маршрутизуєте за межі сервера

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

Що це означає: Сервер не маршрутизує пакети між інтерфейсами.
Рішення: Тримайте вимкненим, якщо не потрібно. Якщо робите full tunnel або site‑to‑site, ввімкніть цілеспрямовано і додайте правила брандмауера.

cr0x@server:~$ sudo sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
cr0x@server:~$ sudo bash -c 'printf "net.ipv4.ip_forward=1\n" > /etc/sysctl.d/99-wireguard-forward.conf'

Завдання 14: додати NAT для full‑tunnel клієнтів (тільки коли ви цього маєте на увазі)

Якщо ви хочете, щоб клієнти використовували VPS як вихід в інтернет, потрібно NAT‑увати трафік з wg0 до eth0. Без цього отримаєте «підключено, але без інтернету».

cr0x@server:~$ sudo nft add table ip nat
cr0x@server:~$ sudo nft 'add chain ip nat postrouting { type nat hook postrouting priority 100 ; }'
cr0x@server:~$ sudo nft add rule ip nat postrouting oif "eth0" ip saddr 10.6.0.0/24 masquerade
cr0x@server:~$ sudo nft list table ip nat
table ip nat {
	chain postrouting {
		type nat hook postrouting priority srcnat; policy accept;
		oif "eth0" ip saddr 10.6.0.0/24 masquerade
	}
}

Що це означає: Трафік клієнтів вийде в інтернет з публічної IP‑адреси сервера.
Рішення: Якщо вам не потрібен full tunnel, не робіть цього. NAT ховає помилки як «воно працює», поки потім не знадобиться прозорість у site‑to‑site.

Завдання 15: перевірити лічильники фаєрвола під час тесту

cr0x@server:~$ sudo nft list chain inet filter input
chain input {
	type filter hook input priority filter; policy drop;
	ct state established,related accept
	iif "lo" accept
	udp dport 51820 accept
	ip saddr 203.0.113.10 tcp dport 22 accept
	ip protocol icmp accept
	ip6 nexthdr icmpv6 accept
	counter packets 12 bytes 672 reject with icmpx type port-unreachable
}

Що це означає: Лічильник reject інкрементується, коли випадковий інтернет‑шум досягає вас.
Рішення: Якщо лічильники несподіваних accept зростають (наприклад SSH), посильте правила. Якщо лічильники UDP 51820 залишаються нульовими під час спроб підключення клієнта — ви насправді не досягаєте хоста: перевірте правила провайдера.

Завдання 16: зняття пакету при «рукостискання не відбувається»

cr0x@server:~$ sudo tcpdump -n -i 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
12:44:10.112233 IP 203.0.113.77.49822 > 198.51.100.25.51820: UDP, length 148
12:44:10.212244 IP 203.0.113.77.49822 > 198.51.100.25.51820: UDP, length 148
5 packets captured

Що це означає: Пакети доходять до сервера. Якщо wg все одно не показує рукопитання, проблема, ймовірно, у ключах, конфігурації peer або AllowedIPs.
Рішення: Якщо tcpdump нічого не показує, припиніть змінювати конфіги WireGuard і виправляйте досяжність (фаєрвол провайдера/security group, NAT, порт‑форвард, неправильна IP).

Маршрутизація та NAT: split‑тунель vs full‑тунель без самосаботажу

Split tunnel: мінімальний ризик, мінімальні сюрпризи

У split tunnel клієнт направляє в VPN лише певні підмережі. Типові AllowedIPs на клієнті:

  • 10.6.0.0/24 — щоб дістатися інших VPN‑peer
  • 192.168.50.0/24 — щоб дістатися домашньої LAN через site‑to‑site peer

Плюси:

  • Менше шансів зламати інтернет‑доступ клієнта.
  • Менше навантаження на сервер.
  • Менше драми на кшталт «чому Netflix у іншій країні».

Мінус: ви не ховаєте весь трафік від локальної мережі. Якщо вам це потрібно (ворожий Wi‑Fi), тимчасово використайте full tunnel.

Full tunnel: потужний, ламає швидше

Full tunnel означає, що клієнт направляє 0.0.0.0/0 (і ::/0 для IPv6) через VPN. Це тягне за собою:

  • NAT або належну маршрутизацію на сервері.
  • Уважну роботу з DNS, щоб уникнути витоків чи відмов.
  • MTU‑проблеми стають помітнішими, бо все йде через тунель.

Рядок у клієнтському конфігу — різниця між «приємним інструментом» і «залежністю від мережі»:

  • Split: AllowedIPs = 10.6.0.0/24, 192.168.50.0/24
  • Full: AllowedIPs = 0.0.0.0/0, ::/0

Site‑to‑site через VPS: чистий спосіб дістатися додому без відкриття портів вдома

Запустіть WireGuard на невеликому пристрої вдома (роутер, міні‑ПК, NAS, якщо мусите) як peer, що підключається вихідно до VPS.
На VPS додайте peer з AllowedIPs, що дорівнюють вашій домашній LAN‑підмережі. На домашньому peer додайте маршрут і правила фаєрвола для форвардингу між wg0 і lan0.

Два важливі запобіжники:

  • Лише один peer повинен «володіти» певним маршрутом у AllowedIPs. Якщо два peeri претендують на 192.168.50.0/24, трафік піде до того, хто був доданий останнім (і ви будете нещасні).
  • На домашньому боці форвардинг — не опція. Ви створюєте роутер. Поводьтеся відповідно.

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

Коли WireGuard «не працює», люди метушаться: міняють порти, перевстановлюють пакети, перезавантажують і потім оголошують перемогу з неправдивих причин. Ось послідовність, що швидко знаходить вузьке місце.

По‑перше: чи досягають пакети UDP‑порту сервера?

  • На сервері: ss -lunp | grep 51820 (слухає чи ні?)
  • На сервері під час спроби підключення: tcpdump -n -i eth0 udp port 51820 (дходять пакети?)
  • У хмарі: переконайтесь, що провайдерський фаєрвол/security group дозволяє UDP 51820.

Якщо пакети не доходять — інше не має значення. Виправляйте мережевий шлях.

По‑друге: чи WireGuard формує рукостискання?

  • wg show → перевірте «latest handshake»
  • Якщо рукописка немає: невірний endpoint IP/порт, неправильні ключі або серверний фаєрвол кидає UDP.

По‑третє: чи проходить трафік в тунелі?

  • Запінгуйте wg‑IP сервера з клієнта.
  • На сервері: дивіться, чи збільшуються лічильники transfer у wg show.
  • Якщо рукостискання є, але трафік не проходить — підозрюйте невідповідність AllowedIPs, фаєрвол на wg0 або MTU.

По‑четверте: маршрутизація/NAT і DNS (категорія «підключено, але марно»)

  • Split tunnel: переконайтесь, що на клієнті є маршрути для очікуваних приватних підмереж.
  • Full tunnel: переконайтесь, що сервер має masquerade і forwarding увімкнені.
  • DNS: переконайтесь, що клієнт вказує резолвер, доступний через обраний режим маршрутизації.

По‑пʼяте: вузькі місця продуктивності

  • Перевірте MTU і симптоми фрагментації першими (повільний HTTPS, затримки, деякі сайти падають).
  • Перевірте завантаження CPU на сервері (дешевий VPS + великий трафік може бути вузьким місцем).
  • Перевірте path MTU і поведінку carrier‑grade NAT, якщо ви на мобільних мережах.

Жарт №2: Налагодження VPN — як сантехніка: 99% часу проблема там, де ви не дивились, бо було «очевидно».

Типові помилки (симптом → причина → виправлення)

1) Симптом: «Рукостискання ніколи не відбувається»

Причина: UDP‑порт заблоковано зверху (фаєрвол хмари, ISP, неправильний порт‑форвард), або в клієнтському конфігу невірний endpoint IP/порт.

Виправлення: Перевірте ss, що сервер слухає, потім tcpdump, щоб побачити вхідний UDP. Якщо пакети не доходять — виправляйте зовнішні правила перед тим, як міняти конфіги WireGuard.

2) Симптом: «Рукостискання відбувається, але я не можу запінгувати 10.6.0.1»

Причина: Фаєрвол сервера відкидає трафік на wg0 (input‑ланцюг не дозволяє), або Address/AllowedIPs клієнта невірні.

Виправлення: Дозвольте input на wg0 або дозволіть ICMP для дебагу; підтвердіть, що Address клієнта — 10.6.0.2/32 і AllowedIPs сервера включає 10.6.0.2/32.

3) Симптом: «Підключено, але немає інтернету у full tunnel»

Причина: Відсутній IP‑форвардинг і/або NAT masquerade на сервері.

Виправлення: Увімкніть net.ipv4.ip_forward=1 і додайте nftables masquerade з wg‑підмережі на egress‑інтерфейс.

4) Симптом: «Деякі сайти завантажуються, інші зависають (особливо HTTPS)»

Причина: Невідповідність MTU, що викликає фрагментацію/чорні діри.

Виправлення: Зменшіть MTU на wg0 (спробуйте 1420 → 1380 → 1360). При PPPoE або подвійних тунелях часто потрібен менший MTU.

5) Симптом: «Один клієнт виводить іншого з мережі»

Причина: Два peeri налаштовані з перекриваючимися AllowedIPs (наприклад, обидва претендують на 10.6.0.2/32 або одну і ту ж LAN‑підмережу).

Виправлення: Зробіть AllowedIPs унікальними. Використовуйте /32 для кожного клієнта. Для site‑підмереж переконайтесь, що лише один peer рекламує кожну підмережу.

6) Симптом: «VPN працює з домашнього Wi‑Fi, але не з мобільного»

Причина: NAT провайдера мобільної мережі / stateful‑фаєрвол, який таймаутить UDP‑мапи; немає keepalive.

Виправлення: Встановіть PersistentKeepalive = 25 на клієнті. Не ставте його на сервері для roaming‑клієнтів; клієнт — той, хто за NAT.

7) Симптом: «VPN увімкнено, але не можу дістатися домашньої LAN через VPS»

Причина: Home peer не форвардить між LAN і wg0, або на пристроях LAN відсутні зворотні маршрути.

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

8) Симптом: «Витікає DNS або дивне розділення резолюції»

Причина: Клієнт використовує локальний DNS, незважаючи на маршрутизацію внутрішніх імен через VPN, або ви вказали DNS на внутрішній резолвер, недоступний у split tunnel.

Виправлення: У split tunnel або тримайте публічний DNS, або маршрутизовуйте до внутрішнього DNS і включіть його підмережу в AllowedIPs. У full tunnel вкажіть DNS явно і перевірте, що він доступний через тунель.

Три короткі історії з корпоративного життя

Міні‑історія 1: Інцидент через хибне припущення

Середня компанія хотіла швидкий VPN для інженерів на чергуванні. План був «просто»: розгорнути WireGuard на VM в хмарі, дозволити інженерам підключатися і маршрутизувати до продакшн‑підмереж. Інженер, що це впроваджував, припустив, що security group хмари вже дозволяє UDP, бо «ми дозволяємо веб‑трафік».

У понеділок вночі один з інженерів спробував підключитися під час інциденту. У клієнтському GUI відображалося «підключено», бо інтерфейс локально піднявся. Але сервер ніколи не бачив рукописання. Люди годину ганялися за ключами, конфігами і MTU, бо це ручки, якими можна крутити, не питаючи нікого.

Справжня проблема: UDP 51820 був заблокований на шарі провайдера. Сервер слухав. OS‑фаєрвол був правильний. Але пакети ніколи не доходили. Команда вважала, що «фаєрвол сервера» — це єдиний фаєрвол.

Фікс був тривіальний: додати одне inbound правило UDP на краю хмари. Урок був дорогий: перевіряйте досяжність першим і документуйте, де реально живе політика. Хмарні мережі шаруваті, і кожен шар — шанс впевнено помилитися.

Міні‑історія 2: Оптимізація, що відкотилася проти них

Інша організація використовувала WireGuard як хаб для розробників. Хтось помітив, що додавання peer і маршрутів ускладнює конфіги. Їхня «оптимізація» — розширити AllowedIPs скрізь: замість /32 для кожного клієнта вони вказали 10.6.0.0/24 для кожного peer на сервері, думаючи, що це зменшить ротацію.

Воно працювало, поки не перестало. Ноутбук одного розробника підключився і тихо перехопив трафік, призначений іншим peer. Не навмисно — просто тому, що WireGuard тепер вірив, що цей peer може відправляти трафік за всю підмережу. Маршрути стали невизначеними залежно від порядку додавання peer і стану інтерфейсу.

Симптоми були чудово хаотичні: двоє інженерів підключалися нормально, третій підключався, але не діставався до внутрішніх сервісів, і іноді проблема «виправлялася» після перезапуску wg0. Це найкращі відмови — вони навчають смиренності і матюкам одночасно.

Відкат полягав у поверненні строгих AllowedIPs: /32 для road‑warrior і лише конкретні підмережі для site‑peer. Управління стало трохи бруднішим. Мережа перестала бути привидом. Це хороша ціна.

Міні‑історія 3: Нудна, але правильна практика, що врятувала день

Команда з фінансової сфери запускала WireGuard для набору автоматизованих агентів у кількох VPC. Установка була неефектною: один крихітний VM як хаб, один UDP‑порт відкритий, SSH тільки з підмережі управління, і nftables з явними forward‑політиками. Вони також мали рукопис: «досяжність → рукостискання → маршрути → DNS».

Під час інциденту провайдера пакетні втрати і латентність зросли. Автоматизовані агенти почали падати. Команда не панікувала і не перепрошувала. Вони взяли рукопис і виконали його, ніби платили оренду за це.

Вони швидко довели: UDP‑пакети доходять, рукищання свіжі, лічильники transfer зростають. Це відсікло більшість локальних причин. Далі вони перевірили помилки інтерфейсу і MTU: чисто. На тому етапі вони ескалували до провайдера з доказами, а не відчуттями.

Провайдер вирішив проблему пізніше, але ключовий момент: команда уникла самоінфікованих ран. Нудна практика була не в «наявності WireGuard». Вона була у повторюваному плані діагностики і фаєрвол‑політиці, що не змінювалася під час стресу.

Поширені запитання

1) Чи потрібно змінювати стандартний порт WireGuard заради безпеки?

Не заради безпеки. Безпека WireGuard походить від ключів, а не від номерів портів. Зміна порту може зменшити випадковий шум сканерів. Якщо змінюєте — змініть скрізь і задокументуйте.

2) Чи можна запускати WireGuard і тримати SSH закритим у інтернеті?

Так, і часто це правильне рішення. Підніміть WireGuard спочатку через консоль/оут‑оф‑банд, потім обмежте SSH до VPN‑підмережі (або до бастіону). Якщо не впевнені, що не заблокуєте себе — тримайте обмежений шлях управління.

3) Що мінімально потрібно виставити в інтернет?

Один UDP‑порт до хоста WireGuard (наприклад 51820/udp). Решта має бути заблокована або обмежена до довірених джерел.

4) Як заборонити клієнту доступ до всієї моєї LAN?

Два рівні: тримайте AllowedIPs клієнта обмеженими (не маршрутизовуйте LAN до нього), і застосуйте правила форвардингу на сервері (скидайте wg0 → lan трафік, якщо не дозволено).

5) Використовувати NAT чи маршрутизацію для site‑to‑site?

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

6) Чому «підключено» не означає «працює»?

Багато клієнтів показують «підключено», коли інтерфейс локально піднявся, навіть без рукостискання. Довіряйте wg show і лічильникам пакетів, а не статус‑значкам UI.

7) Чи потрібен PersistentKeepalive?

Для роумінгових клієнтів за NAT (мобільні, готелі) — так, часто потрібен. Встановіть його на клієнті, наприклад 25 секунд. На сервері з публічною IP зазвичай ні.

8) Чи безпечно використовувати WireGuard у продакшені?

Так, за наявності розумної моделі розгортання: мінімум відкритих сервісів, суворі AllowedIPs для peer, явне фаєрволювання і план ротації ключів та виведення з експлуатації. Більшість «VPN‑інцидентів» — це помилки маршрутизації і політики, а не криптографічні провали WireGuard.

9) Що з IPv6?

Якщо у вас є IPv6, ставтеся до нього як до першокласного громадянина: призначайте IPv6‑адреси на wg0, включайте ::/0 лише якщо ви маєте на увазі full‑tunnel IPv6, і пишіть IPv6‑правила фаєрвола. Ігнорування IPv6 — частий спосіб випадково створити «зайві діри», які ви не моніторите.

10) Як обертати ключі без простою?

Додайте новий peer‑ключ (або оновіть peer), залишивши старий короткий час, потім видаліть старий після підтвердження підключень клієнтів. На практиці: плануйте зміни, верифікуйте рукостискання, потім очищуйте. Не робіть одномоментної ротації, якщо не любите несподівані дзвінки.

Висновок: наступні кроки, які ви можете зробити сьогодні

Якщо ви візьмете одну ідею з цього: відкривайте один UDP‑порт і будьте явними щодо всього іншого. WireGuard простий настільки, що ви можете тримати всю систему в голові — поки не почнете додавати «корисні» скорочення.

Практичні кроки:

  1. Виберіть топологію (VPS‑хаб зазвичай найменш болісний) і запишіть підмережі, які будете маршрутизувати.
  2. Реалізуйте фаєрвол за замовчуванням drop з явними дозволами для UDP 51820 і обмеженим SSH.
  3. Налаштуйте peeri з жорсткими AllowedIPs (/32 для кожного клієнта) і протестуйте рукостискання та лічильники через wg show.
  4. Якщо потрібен full tunnel — ввімкніть форвардинг і NAT цілеспрямовано, а потім перевірте поведінку DNS.
  5. Вставте (або роздрукуйте) Швидкий план діагностики у ваш рукопис. Ваш майбутній себе скаже вам «дякую» у вигляді менше відмов.
← Попередня
ZFS SLOG: коли лог-пристрій допомагає, коли марний, коли небезпечний
Наступна →
Кешування BuildKit, яке справді прискорює збірку Docker

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