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 → як з'єднатись?

Рішення

  1. Один peer з public IP (рекомендовано)
    Peer A (NAT) → Peer B (public) — працює

  2. UDP Hole Punching (складно)
    Потрібен STUN сервер для координації Не завжди працює (symmetric NAT)

  3. 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

Див. також

Шлях: networking/vpn/wireguard-advanced.md

UMTC Wiki © 2026 | Ukrainian Military Tactical Communications