Зачем 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:
[Interface]
PrivateKey = <server-private-key>
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 = <client-public-key>
AllowedIPs = 10.10.0.2/32
Клиент wg0.conf:
[Interface]
PrivateKey = <client-private-key>
Address = 10.10.0.2/24
DNS = 1.1.1.1
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0 # full-tunnel; для split-tunnel - конкретные подсети
PersistentKeepalive = 25 # за NAT'ом, держит conntrack-запись
Запуск:
wg-quick up wg0
systemctl enable wg-quick@wg0 # автостарт
Генерация ключей
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
Приватный ключ никогда не покидает машину. Конфиг хранит его
открытым текстом, поэтому права 600 на /etc/wireguard/.
Секретный ключ всегда генерируется на peer'е, не на сервере.
PSK (опционально, для quantum-resistance):
wg genpsk > preshared.key
и в [Peer]: PresharedKey = <psk>.
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 (мобильный оператор), нужен.
Диагностика
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 | ipsec-ike |
|---|---|---|---|
| Кодовая база | ~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выключен на сервере; либо нет 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).