# WireGuard - современный UDP-VPN _Протоколы · LinuxLab Knowledge Base_ **TL;DR:** WireGuard - UDP-VPN в ядре Linux. Пара ключей Curve25519, peers с AllowedIPs (это и ACL, и routing-table). ~4000 строк кода против миллионов у OpenVPN/IPsec. Конфиг плоский, без TLS и сертификатов. ## Зачем WireGuard Появился в 2016, в mainline kernel с 5.6 (2020). Цель: VPN без гипер-сложности [[ipsec-ike|IPsec]] и без оверхеда [[openvpn|OpenVPN]]. Что получилось: - **Один тип пакета** (UDP), один cipher-suite (ChaCha20-Poly1305 + Curve25519), без negotiation. Если будущие primitives устареют выйдет WireGuard 2. - **Stateless с точки зрения админа**: пара ключей на каждой стороне, публичный ключ peer'а, единственный identifier. - **AllowedIPs**, одновременно ACL (что peer может слать) и routing-table (куда заворачивать пакеты на этот peer). - **Roaming**: peer может менять IP/порт без переподключения, потому что аутентификация по ключу, не по 5-tuple. ## Базовый конфиг Серверная сторона `/etc/wireguard/wg0.conf`: ```ini [Interface] PrivateKey = Address = 10.10.0.1/24 ListenPort = 51820 PostUp = iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE PostDown = iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o eth0 -j MASQUERADE [Peer] PublicKey = AllowedIPs = 10.10.0.2/32 ``` Клиент `wg0.conf`: ```ini [Interface] PrivateKey = Address = 10.10.0.2/24 DNS = 1.1.1.1 [Peer] PublicKey = Endpoint = vpn.example.com:51820 AllowedIPs = 0.0.0.0/0, ::/0 # full-tunnel; для split-tunnel - конкретные подсети PersistentKeepalive = 25 # за NAT'ом, держит conntrack-запись ``` Запуск: ```bash wg-quick up wg0 systemctl enable wg-quick@wg0 # автостарт ``` ## Генерация ключей ```bash umask 077 wg genkey | tee privatekey | wg pubkey > publickey ``` Приватный ключ **никогда не покидает** машину. Конфиг хранит его открытым текстом, поэтому права 600 на `/etc/wireguard/`. Секретный ключ всегда генерируется на peer'е, не на сервере. PSK (опционально, для quantum-resistance): ```bash wg genpsk > preshared.key ``` и в [Peer]: `PresharedKey = `. ## AllowedIPs, самое важное поле ``` AllowedIPs = 10.10.0.2/32 # один host AllowedIPs = 10.10.0.0/24, 192.168.5.0/24 # несколько подсетей AllowedIPs = 0.0.0.0/0, ::/0 # ВСЁ - full-tunnel ``` - **Входящий пакет** от peer'а: src должен попадать в AllowedIPs, иначе drop. Это и есть аутентификация trust-границы. - **Исходящий пакет**: если dst попадает в AllowedIPs какого-то peer'а, wg0 направляет на него. Аналогично routing. Поэтому одна и та же подсеть `10.10.0.0/24` не может быть в AllowedIPs у двух peer'ов одновременно, конфликт routing. ## Роли: hub-and-spoke vs full-mesh WireGuard на L3 не различает "сервер" и "клиент", оба peers равны. Topology, это просто кто кому что прописал в `[Peer]`: - **Hub**: один peer со всеми peer-блоками; AllowedIPs у каждого клиента, узкая. Простая модель, классический "VPN-сервер". - **Mesh**: каждый знает каждого. Сложнее провижионить, но трафик напрямую без хопа через hub. - **Tailscale/Headscale** автоматизируют mesh поверх WireGuard. ## NAT и keepalive За NAT'ом запись в conntrack умирает за 30-180 секунд если нет трафика. WireGuard про это знает, `PersistentKeepalive = 25` шлёт пустой keepalive каждые 25 секунд, чтобы дыра в NAT'е жила. Hub за статическим IP `PersistentKeepalive` не нужен. Клиент за CGNAT (мобильный оператор), нужен. ## Диагностика ```bash wg show # все интерфейсы и peers wg show wg0 # детали одного wg show wg0 dump # машинно-читаемый формат wg show wg0 latest-handshakes # когда последний handshake wg show wg0 transfer # rx/tx bytes на peer ``` Главный индикатор живой связи, **latest handshake** должен обновляться раз в ~2 минуты. Если показывает "30 minutes ago" peer недостижим. ## WireGuard vs OpenVPN vs IPsec | Признак | WireGuard | [openvpn](/kb/openvpn.md) | [ipsec-ike](/kb/ipsec-ike.md) | |---------|-----------|-------------|---------------| | Кодовая база | ~4 KLOC | ~600 KLOC | млн (strongSwan) | | Где живёт | в ядре | userspace | в ядре + IKE userspace | | Конфиг | плоский ini | nested + certs | swanctl.conf + сертификаты | | Cipher | ChaCha20-Poly1305 (фиксирован) | TLS suite | IKEv2-negotiated | | UDP | да | да или TCP | да (ESP) | | Roaming | нативно | нет | мoblike-расширение | | Performance | заметно быстрее | медленнее (userspace) | сравнимо с WG | | Production-зрелость | 2020+ | 2002+ | 1995+ | | Сертификаты / PKI | нет | да | да | Когда не WireGuard: - Нужен PKI (corp с CRL/OCSP) → IPsec/OpenVPN - Нужен TCP fallback (port 443 как маскировка) → OpenVPN - Per-user-аутентификация с RADIUS/LDAP → OpenVPN - Стандарт для interop с Cisco/Juniper → IPsec ## Когда что-то пошло не так - **`No such device wg0`**, модуль не загружен. На kernel 5.6+ встроен; на старых нужен `wireguard-dkms`. `modprobe wireguard`. - **Handshake не происходит**, UDP 51820 закрыт по пути. Проверь `nc -u -z -v server 51820`, фаервол на хосте, NAT. - **Handshake есть, трафик не ходит**, `ip route` не имеет route'а на VPN-подсеть; либо `[ip-forwarding](/kb/ip-forwarding.md)` выключен на сервере; либо нет MASQUERADE. - **Слишком жирный пакет дропается**, MTU. WG-overhead 60 байт (UDP + headers); ставь `MTU = 1420` явно если канал имеет MTU 1500. - **`Address already in use` при wg-quick up**, IP уже занят на другом интерфейсе (старый wg0 не выключен). `wg-quick down wg0`. - **AllowedIPs пересекаются у двух peers**, последний выигрывает, остальные становятся unreachable. Не пересекай подсети. - **`PersistentKeepalive` слишком частый**, лишний батарея на мобильных клиентах. 25 сек, компромисс с NAT (60s typical). ## Команды ```bash wg genkey | tee privatekey | wg pubkey > publickey ``` Сгенерировать пару ключей одной строкой - private + public ```bash wg-quick up wg0 ``` Поднять интерфейс с конфигом /etc/wireguard/wg0.conf ```bash wg show wg0 latest-handshakes ``` Когда последний handshake с каждым peer'ом - живая ли связь ```bash wg show wg0 transfer ``` Сколько rx/tx байт ушло-пришло через peer - индикатор активности ```bash wg syncconf wg0 <(wg-quick strip wg0) ``` Подхватить изменения в конфиге без перезапуска интерфейса ```bash ip -d link show wg0 ``` Параметры интерфейса - MTU, статистика, тип ```bash tcpdump -i any -nn 'udp port 51820' -c 5 ``` Видны ли WireGuard-пакеты на проводе - первое что смотреть при no-handshake ## См. также - [OpenVPN - TLS-based VPN](/kb/openvpn.md) - [IPsec и IKEv2 - стандарт корпоративных VPN](/kb/ipsec-ike.md) - [UDP - User Datagram Protocol](/kb/udp-basics.md) - [NAT и masquerade](/kb/nat.md) - [nft - современный файрвол (nftables)](/kb/cmd-nft.md)