WireGuard — поглиблений гайд¶
WireGuard — сучасний VPN протокол, що поєднує простоту, швидкість та безпеку. Цей гайд розглядає просунуті аспекти: криптографію, mesh топології, оптимізацію та troubleshooting.
Чому WireGuard?¶
Порівняння з іншими VPN¶
| Аспект | WireGuard | OpenVPN | IPsec |
|---|---|---|---|
| Код | ~4000 рядків | ~100000 | ~400000 |
| Швидкість | Найвища | Середня | Висока |
| Криптографія | Сучасна, фіксована | Налаштовується | Налаштовується |
| Аудит | Простий | Складний | Дуже складний |
| Handshake | 1 RTT | 2+ RTT | Багато RTT |
| Statefulness | Stateless | Stateful | Stateful |
Переваги WireGuard¶
┌─────────────────────────────────────────────────────────────────┐
│ ПЕРЕВАГИ WIREGUARD │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ✓ Простота │
│ - Мінімальна конфігурація │
│ - Легкий troubleshooting │
│ - Код можна прочитати за вечір │
│ │
│ ✓ Швидкість │
│ - В ядрі Linux (kernel module) │
│ - ChaCha20 — швидкий на ARM без AES-NI │
│ - ~1 Gbps на Raspberry Pi 4 │
│ │
│ ✓ Безпека │
│ - Сучасні криптографічні примітиви │
│ - Немає вибору — немає помилок конфігурації │
│ - Криптографічна маршрутизація │
│ │
│ ✓ Roaming │
│ - Автоматичне відновлення при зміні IP │
│ - Працює при переході WiFi ↔ LTE │
│ │
└─────────────────────────────────────────────────────────────────┘
Криптографія¶
Noise Protocol Framework¶
WireGuard використовує Noise_IK handshake:
┌─────────────────────────────────────────────────────────────────┐
│ WIREGUARD HANDSHAKE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Initiator Responder │
│ │ │ │
│ │ Handshake Initiation │ │
│ │ ─────────────────────────────────> │ │
│ │ ephemeral_pub, encrypted_static, │ │
│ │ encrypted_timestamp, MAC │ │
│ │ │ │
│ │ Handshake Response │ │
│ │ <───────────────────────────────── │ │
│ │ ephemeral_pub, encrypted_nothing, │ │
│ │ MAC │ │
│ │ │ │
│ │ [Symmetric keys derived] │ │
│ │ │ │
│ │ Encrypted Data │ │
│ │ <════════════════════════════════> │ │
│ │ │ │
│ │
│ 1-RTT handshake (vs 2+ RTT для TLS) │
│ │
└─────────────────────────────────────────────────────────────────┘
Криптографічні примітиви¶
| Примітив | Використання |
|---|---|
| Curve25519 | ECDH для обміну ключами |
| ChaCha20 | Симетричне шифрування |
| Poly1305 | Автентифікація (MAC) |
| BLAKE2s | Хешування |
| HKDF | Деривація ключів |
# Всі примітиви — сучасні та швидкі
# Особливо ChaCha20-Poly1305 на ARM без AES-NI
# Benchmark на MikroTik hAP ax3:
# AES-GCM: ~300 Mbps
# ChaCha20: ~500 Mbps
Ключі¶
# Генерація ключів
wg genkey > private.key
wg pubkey < private.key > public.key
# Або одним рядком
wg genkey | tee private.key | wg pubkey > public.key
# Pre-shared key (додатковий захист)
wg genpsk > psk.key
Private key — 32 байти Curve25519 scalar
Public key — 32 байти Curve25519 point
Pre-shared key — 32 байти симетричний ключ (опціонально)
Криптографічна маршрутизація (Cryptokey Routing)¶
┌─────────────────────────────────────────────────────────────────┐
│ CRYPTOKEY ROUTING │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Звичайна маршрутизація: │
│ Destination IP → Interface → Next hop │
│ │
│ WireGuard: │
│ Destination IP → Peer public key → Encrypt → Send │
│ │
│ Приклад: │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ [Peer] │ │
│ │ PublicKey = ABC123... │ │
│ │ AllowedIPs = 10.0.0.2/32, 192.168.2.0/24 │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ Вихідний пакет до 192.168.2.100: │
│ 1. Знаходимо peer з AllowedIPs що містить 192.168.2.100 │
│ 2. Шифруємо public key цього peer │
│ 3. Відправляємо на endpoint peer │
│ │
│ Вхідний пакет: │
│ 1. Дешифруємо, визначаємо peer по ключу │
│ 2. Перевіряємо чи source IP в AllowedIPs peer │
│ 3. Якщо ні — DROP │
│ │
│ AllowedIPs = одночасно: │
│ - Таблиця маршрутизації (для вихідних) │
│ - ACL (для вхідних) │
│ │
└─────────────────────────────────────────────────────────────────┘
Mesh топологія¶
Full Mesh¶
┌─────────────────────────────────────────────────────────────────┐
│ FULL MESH │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Node A (10.0.0.1) │
│ / \ │
│ / \ │
│ / \ │
│ / \ │
│ Node B ─────────────── Node C │
│ (10.0.0.2) (10.0.0.3) │
│ │
│ Кожен з кожним напряму. │
│ N nodes = N(N-1)/2 з'єднань │
│ 3 nodes = 3 з'єднання │
│ 10 nodes = 45 з'єднань │
│ │
│ Переваги: │
│ + Оптимальна затримка │
│ + Немає single point of failure │
│ │
│ Недоліки: │
│ - Складність конфігурації O(n²) │
│ - Не масштабується │
│ │
└─────────────────────────────────────────────────────────────────┘
Hub and Spoke¶
┌─────────────────────────────────────────────────────────────────┐
│ HUB AND SPOKE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Hub (10.0.0.1) │
│ / | \ │
│ / | \ │
│ / | \ │
│ Spoke A Spoke B Spoke C │
│ (10.0.0.2)(10.0.0.3)(10.0.0.4) │
│ │
│ Всі підключаються до центрального сервера. │
│ N nodes = N-1 з'єднань │
│ │
│ Переваги: │
│ + Проста конфігурація │
│ + Масштабується │
│ + Hub може фільтрувати трафік │
│ │
│ Недоліки: │
│ - Трафік через hub (затримка) │
│ - Hub = single point of failure │
│ │
└─────────────────────────────────────────────────────────────────┘
Приклад mesh на MikroTik¶
# Node A (Hub): 10.0.0.1, public IP 203.0.113.1
/interface wireguard add listen-port=51820 name=wg0 private-key="<A_PRIVATE>"
/interface wireguard peers
add allowed-address=10.0.0.2/32,192.168.2.0/24 interface=wg0 \
public-key="<B_PUBLIC>" endpoint-address=203.0.113.2 endpoint-port=51820
add allowed-address=10.0.0.3/32,192.168.3.0/24 interface=wg0 \
public-key="<C_PUBLIC>" endpoint-address=203.0.113.3 endpoint-port=51820
/ip address add address=10.0.0.1/24 interface=wg0
# Маршрути до мереж за nodes
/ip route add dst-address=192.168.2.0/24 gateway=wg0
/ip route add dst-address=192.168.3.0/24 gateway=wg0
AllowedIPs детально¶
Як працює¶
AllowedIPs = 10.0.0.2/32, 192.168.2.0/24
Означає:
1. ВИХІДНІ пакети на 10.0.0.2 або 192.168.2.0/24
→ шифруються цим peer
2. ВХІДНІ пакети від цього peer
→ можуть мати source IP тільки з цих діапазонів
Типові значення¶
# Тільки peer IP (point-to-point)
AllowedIPs = 10.0.0.2/32
# Peer + мережа за ним
AllowedIPs = 10.0.0.2/32, 192.168.2.0/24
# Весь трафік через peer (VPN gateway)
AllowedIPs = 0.0.0.0/0, ::/0
# Декілька мереж
AllowedIPs = 10.0.0.2/32, 192.168.2.0/24, 172.16.0.0/16
Split Tunnel vs Full Tunnel¶
┌─────────────────────────────────────────────────────────────────┐
│ │
│ SPLIT TUNNEL (рекомендовано): │
│ AllowedIPs = 10.0.0.0/24, 192.168.100.0/24 │
│ │
│ Client │
│ │ │
│ ├── 10.0.0.x, 192.168.100.x → через WireGuard │
│ │ │
│ └── google.com, youtube.com → напряму в інтернет │
│ │
│ + Менше навантаження на VPN сервер │
│ + Швидший інтернет для клієнта │
│ │
│ ──────────────────────────────────────────────────────────── │
│ │
│ FULL TUNNEL: │
│ AllowedIPs = 0.0.0.0/0 │
│ │
│ Client │
│ │ │
│ └── ВСЕ → через WireGuard → Інтернет │
│ │
│ + Весь трафік захищений │
│ + Приховує реальний IP клієнта │
│ - Більше навантаження │
│ - Затримка для всього трафіку │
│ │
└─────────────────────────────────────────────────────────────────┘
PersistentKeepalive¶
Навіщо потрібен?¶
┌─────────────────────────────────────────────────────────────────┐
│ │
│ Peer A (за NAT) Peer B (public IP) │
│ 192.168.1.100 203.0.113.1 │
│ │ │ │
│ │ NAT state table │ │
│ ┌────┴────┐ │ │
│ │ NAT │ │ │
│ │ router │ │ │
│ └────┬────┘ │ │
│ │ │ │
│ Peer A відправляє → NAT створює запис → Peer B отримує │
│ Peer B відповідає → NAT пропускає (є запис) │
│ │
│ Проблема: NAT таблиця очищається через ~60-300 сек │
│ Якщо немає трафіку → запис видаляється → зв'язок втрачено │
│ │
│ Рішення: PersistentKeepalive = 25 │
│ Кожні 25 сек відправляється keepalive пакет │
│ NAT запис оновлюється, тунель живий │
│ │
└─────────────────────────────────────────────────────────────────┘
Коли використовувати?¶
# Потрібен якщо:
# - Peer за NAT
# - Peer ініціює з'єднання ззовні (сервер хоче достукатись до клієнта)
# - Нестабільна мережа
# НЕ потрібен якщо:
# - Обидва peer з public IP
# - Клієнт завжди ініціює з'єднання сам
# - Постійний трафік в обидва боки
# MikroTik
/interface wireguard peers set [find] persistent-keepalive=25
# Linux
[Peer]
PersistentKeepalive = 25
MTU оптимізація¶
Проблема фрагментації¶
┌─────────────────────────────────────────────────────────────────┐
│ MTU ПРОБЛЕМА │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Ethernet MTU = 1500 bytes │
│ │
│ WireGuard overhead: │
│ - IPv4 header: 20 bytes │
│ - UDP header: 8 bytes │
│ - WireGuard header: 32 bytes │
│ - Total: 60 bytes │
│ │
│ WireGuard MTU = 1500 - 60 = 1440 │
│ │
│ Якщо ще PPPoE (8 bytes): │
│ WireGuard MTU = 1500 - 8 - 60 = 1432 │
│ │
│ Що буде якщо MTU занадто великий? │
│ │
│ [1500 byte packet] → [WireGuard] → [1560 byte packet] │
│ │ │
│ ▼ │
│ FRAGMENTATION │
│ або DROP (якщо DF=1) │
│ │
│ Симптоми: │
│ - Ping працює, але великі файли не передаються │
│ - SSH підключається, але висить │
│ - Веб сторінки завантажуються частково │
│ │
└─────────────────────────────────────────────────────────────────┘
Рішення¶
# MikroTik — встановити MTU на WireGuard інтерфейсі
/interface wireguard set wg0 mtu=1420
# Linux
ip link set wg0 mtu 1420
# Або в конфізі
[Interface]
MTU = 1420
# Визначити оптимальний MTU
ping -M do -s 1400 10.0.0.1 # Збільшувати поки не буде fragmented
MSS Clamping (альтернатива)¶
# MikroTik — змінювати MSS в TCP пакетах
/ip firewall mangle add chain=forward protocol=tcp \
tcp-flags=syn in-interface=wg0 \
action=change-mss new-mss=clamp-to-pmtu
# Або фіксоване значення
action=change-mss new-mss=1380
NAT Traversal¶
Проблема подвійного NAT¶
Peer A Peer B
│ │
│ NAT │ NAT
│ │
└──── Internet ───────┘
Жоден не має public IP → як з'єднатись?
Рішення¶
-
Один peer з public IP (рекомендовано)
Peer A (NAT) → Peer B (public) — працює -
UDP Hole Punching (складно)
Потрібен STUN сервер для координації Не завжди працює (symmetric NAT) -
Relay сервер
Peer A → Relay (public) → Peer B Завжди працює, але затримка
Моніторинг та дебаг¶
Linux¶
# Статус інтерфейсу
wg show
# Детальніше
wg show wg0
# interface: wg0
# public key: ABC...
# private key: (hidden)
# listening port: 51820
#
# peer: XYZ...
# endpoint: 203.0.113.1:51820
# allowed ips: 10.0.0.2/32
# latest handshake: 15 seconds ago
# transfer: 1.5 MiB received, 2.3 MiB sent
# Перевірити handshake
# "latest handshake" має бути < 2 хвилини
# Якщо "never" — peer недоступний
MikroTik¶
# Статус peers
/interface wireguard peers print detail
# Rx/Tx лічильники
/interface wireguard peers print stats
# Моніторинг в реальному часі
/interface wireguard peers monitor [find]
# Логи
/system logging add topics=wireguard action=memory
/log print where topics~"wireguard"
Типові проблеми¶
Проблема: "latest handshake: never"
Причина:
- Неправильний endpoint
- Firewall блокує UDP
- Неправильні ключі
Рішення:
- Перевірити ping до endpoint
- Відкрити UDP port
- Перегенерувати ключі
Проблема: Handshake є, але немає трафіку
Причина:
- AllowedIPs не включає потрібні мережі
- Немає маршрутів
- Firewall на peer
Рішення:
- Перевірити AllowedIPs
- Додати маршрути
- Перевірити firewall
Проблема: Періодичні обриви
Причина:
- NAT timeout
- Нестабільний endpoint
Рішення:
- Додати PersistentKeepalive=25
- Перевірити мережу
MikroTik особливості¶
Firewall для WireGuard¶
# Дозволити WireGuard (UDP 51820)
/ip firewall filter add chain=input protocol=udp dst-port=51820 action=accept \
comment="WireGuard"
# Дозволити трафік з wg інтерфейсу (якщо потрібно)
/ip firewall filter add chain=input in-interface=wg0 action=accept \
comment="WireGuard tunnel traffic"
# Forward між WireGuard та LAN
/ip firewall filter add chain=forward in-interface=wg0 out-interface=bridge-lan action=accept
/ip firewall filter add chain=forward in-interface=bridge-lan out-interface=wg0 action=accept
DDNS (динамічний endpoint)¶
# Якщо peer не має статичного IP
# Використовувати доменне ім'я в endpoint
# MikroTik Cloud DDNS
/ip cloud set ddns-enabled=yes
# Отримати ім'я
/ip cloud print
# dns-name: abc123.sn.mynetname.net
# На іншому peer:
endpoint-address=abc123.sn.mynetname.net
Резервування (failover)¶
# Створити два WireGuard інтерфейси
/interface wireguard add name=wg-primary ...
/interface wireguard add name=wg-backup ...
# Налаштувати routing з distance
/ip route add dst-address=10.0.0.0/24 gateway=wg-primary distance=1
/ip route add dst-address=10.0.0.0/24 gateway=wg-backup distance=2
# Netwatch для перевірки
/tool netwatch add host=10.0.0.1 interval=10s \
down-script="/ip route disable [find gateway=wg-primary]" \
up-script="/ip route enable [find gateway=wg-primary]"
Безпека та hardening¶
# 1. Використовувати PSK для постквантової безпеки
wg genpsk > psk.key
# Додати до обох peers
# 2. Обмежити AllowedIPs
# НЕ використовувати 0.0.0.0/0 якщо не потрібно
# 3. Firewall — дозволяти тільки потрібний трафік
/ip firewall filter add chain=forward in-interface=wg0 \
dst-address=192.168.1.0/24 dst-port=22,80,443 protocol=tcp action=accept
# 4. Приховати private key
# Ніколи не показувати в логах
# Зберігати в захищеному місці
# 5. Регулярно оновлювати RouterOS
/system package update check-for-updates
Див. також¶
- MikroTik WireGuard mesh — базове налаштування
- GNS3 — тестування в лабораторії
- SSH ключі — аналогічний підхід до ключів
Шлях: networking/vpn/wireguard-advanced.md