Если у вас есть мобильные или «роумящие» клиенты WireGuard — сотрудники с ноутбуками, смартфоны, IoT‑терминалы — вы точно сталкивались с потерями туннеля при смене сети и IP. Пользователь переходит с LTE на Wi‑Fi, едет между сотами, засыпает телефон, а потом «встает» другой публичный адрес и порт. Правильная настройка роуминга, persistent-keepalive и MTU снимает большую часть этих проблем и делает VPN предсказуемым.
Как WireGuard переживает смену IP (роуминг)
WireGuard не держит «сессию» в классическом понимании. У каждого пира есть ключи и «Endpoint», а актуальный внешний адрес и порт обновляются автоматически по факту получения валидно подписанного пакета. Это и называется роуминг: клиент может менять исходный IP/порт, и сервер примет новое значение, как только прилетит любой зашифрованный пакет от того же пира.
Отсюда ключевые следствия:
- Если клиент за NAT/CGNAT, ему нужно периодически отправлять пакеты наружу, чтобы не протухало UDP‑соответствие на промежуточном устройстве. Для этого служит
PersistentKeepalive. - Роуминг срабатывает только при наличии трафика. Если клиент «молчит», сервер не узнает, что у него поменялся IP/порт, и будет продолжать слать пакеты в пустоту.
- При резкой смене сети (например, Wi‑Fi→LTE) полезно мгновенно инициировать рукопожатие. На iOS/Android это делает официальный клиент сам, на Linux можно дернуть конфиг через
wg setconfили просто дождаться keepalive/трафика.
Таймеры и жизненный цикл рукопожатия
В норме у пира каждые 2 минуты происходит рекей (переустановка ключей), а в простое соединение «усыпается». Когда приходит пользовательский пакет (или keepalive), «Endpoint» обновляется, а туннель «просыпается». Если трафика нет, записи в карте пиров «стареют», и без keepalive роумящий клиент рискует потерять маршрут в ответ.
Простое правило: пир за NAT должен периодически сам стучаться на публичную сторону. Поэтому
PersistentKeepaliveнастраивают на стороне того устройства, которое находится за NAT/CGNAT или часто меняет исходный IP.
Когда и где ставить PersistentKeepalive
PersistentKeepalive — это параметр в блоке [Peer], говорящий локальному устройству «шлём пустой пакет раз в N секунд, даже если нет пользовательского трафика». Ставится там, где мы хотим отправлять keepalive наружу. Для схемы «мобильный клиент → публичный сервер» — в конфиге клиента. Для «офисный роутер за провайдерским NAT → публичный хаб» — в конфиге роутера. Если обе стороны за NAT и инициировать соединение может только одна сторона — keepalive нужен именно на «внутренней» стороне.
Рекомендованное значение
Классическая рекомендация — PersistentKeepalive = 25. Это значение достаточно частое, чтобы не истекал UDP‑таймаут у большинства NAT (обычно 30–120 секунд), и при этом не слишком «прожорливое» для батареи смартфонов. Если наблюдаются обрывы при «молчаливых» клиентах, можно снизить до 20–15, но помните о компромиссе с энергопотреблением.
Сложные NAT и корпоративные сети
В сетях с агрессивными таймаутами и фильтрацией UDP может понадобиться:
- уменьшить интервал до 15 секунд,
- разрешить исходящий UDP на конкретный порт со стороны клиента,
- при невозможности UDP — рассмотреть альтернативные транспортные решения (внутри разрешённой политики). WireGuard по дизайну работает поверх UDP.

MTU для роумящих клиентов
Неправильный MTU проявляется как «залипающие» соединения, особенно в мобильных сетях и при переходе IPv4↔IPv6. У WireGuard есть собственные накладные расходы: поверх UDP добавляется шифрование, и эффективная полезная нагрузка уменьшается. Общепринятые пресеты:
- Базовая Ethernet‑сеть с MTU 1500: ставьте
MTU = 1420на интерфейсе WireGuard. - PPPoE с MTU 1492: используйте
MTU ≈ 1412. - Мобильные/IPv6‑трассы с «хрупким» PMTUD: иногда помогает консервативный
MTU = 1280.
Лучше проверять фактический путь:
- Linux IPv4: подбирайте максимальный размер с
ping -M doи постепенно увеличивайте-sк удалённому адресу за туннелем. - IPv6: используйте
tracepathили аналогичный инструмент для оценки пути.
Если туннель работает, но часть сайтов/сервисов «подвисает» на крупных ответах, первым делом снижайте MTU на 20–40 байт и проверяйте снова. Для роумящих клиентов универсальным компромиссом часто оказывается 1420, а при регулярных обрывах — 1380–1400.

Пример конфигурации: сервер и роумящий клиент
Сервер: публичный адрес, статический порт
Поднять публичную сторону WireGuard проще всего на VDS со стабильным адресом и открытым UDP‑портом.
# /etc/wireguard/wg0.conf
[Interface]
Address = 10.6.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
# По желанию: MTU (чаще достаточно на клиентах)
# MTU = 1420
# Пир: роумящий клиент за NAT
[Peer]
PublicKey = CLIENT_PUBLIC_KEY
PresharedKey = OPTIONAL_PRESHARED_KEY
AllowedIPs = 10.6.0.2/32
# На сервере чаще НЕ ставим PersistentKeepalive, он должен идти от клиента
Клиент: ноутбук/смартфон, роумит между сетями
# /etc/wireguard/wg0.conf (wg-quick на Linux/macOS)
[Interface]
Address = 10.6.0.2/32
PrivateKey = CLIENT_PRIVATE_KEY
DNS = 9.9.9.9
MTU = 1420
[Peer]
PublicKey = SERVER_PUBLIC_KEY
PresharedKey = OPTIONAL_PRESHARED_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = vpn.example.com:51820
PersistentKeepalive = 25
Пояснения:
Endpointможно указывать доменным именем — это удобно, когда у сервера возможна смена IP. Если нужен удобочитаемый адрес, используйте регистрацию доменов и настройте A/AAAA‑записи.AllowedIPsопределяет маршрутизацию через туннель. Для «полного туннеля» используем0.0.0.0/0, ::/0; для «сплит‑туннеля» — только нужные подсети.PersistentKeepaliveустановлен у клиента, потому что именно он находится за NAT и меняет исходный адрес.
Смена IP у клиента: что произойдёт
Как только роумящий клиент отправит очередной пользовательский или keepalive‑пакет с нового адреса/порта, сервер обновит «Endpoint» и продолжит общение уже на новый источник. Пользователь обычно этого не замечает. Проблемы начинаются, если:
- клиент долго молчит, а NAT уже забыл соответствие;
- в новой сети блокируют исходящий UDP или порт сервера;
- сломался PMTUD, и крупные пакеты не проходят (см. MTU).
Решения: уменьшить интервал keepalive, использовать «надежный» порт, уменьшить MTU, включить в клиенте режим автоконнекта при сетевых событиях (в мобильных клиентах это штатная опция).
Смена IP у сервера: не забываем про DNS и re-resolve
Если меняется публичный адрес сервера, а у клиентов в Endpoint указан домен, его нужно переобновить на стороне WireGuard. Большинство десктоп‑клиентов и mobile‑приложений re‑resolve делают при старте/переключении сети. На Linux сервере/клиенте, с wg-quick, можно принудительно «перечитать» конфигурацию или переустановить Endpoint тем же доменным именем, чтобы прошёл новый DNS‑резолв.
# Принудительно перечитать конфиг (короткий даун/ап)
sudo wg-quick down wg0
sudo wg-quick up wg0
# Или атомично синхронизировать конфиг (без даунтайма интерфейса)
sudo wg setconf wg0 /etc/wireguard/wg0.conf
Альтернативно можно периодически запускать задачу, которая переустанавливает Endpoint через wg set с тем же доменным именем, вынуждая re‑resolve в userspace. Это полезно, если сервер иногда получает новый IP от провайдера.
Тонкости AllowedIPs и маршрутизации для роуминга
Частая ошибка — слишком широкие или, наоборот, конфликтующие маршруты. Для точечного доступа к нескольким внутренним подсетям указывайте их явно, избегая пересечений с локальными сетями клиента (например, домашняя 192.168.0.0/24). Если «локалка» клиента совпадает с корпоративной, у роумящего клиента возникнет асимметричная маршрутизация и часть трафика уйдет мимо туннеля.
Советы:
- всегда проверяйте таблицу маршрутов у клиента после поднятия VPN;
- для сплит‑туннеля не используйте дефолт, добавляйте только нужные префиксы;
- если нужен полный туннель, резолв DNS лучше отдавать через VPN, чтобы избежать утечек.
Диагностика: что смотреть при обрывах у «роумящих»
- Статус WireGuard. На обеих сторонах:
wg show. Обратите внимание на latest handshake, счётчики трафика, текущий endpoint. Если рукопожатий давно не было и трафик не растёт, проблема либо в UDP/маршрутизации, либо в MTU. - Проверка UDP и порта. На сервере:
ss -ulpn | grep 51820— слушает ли порт.tcpdump -n -i eth0 udp port 51820— прилетает ли что‑то от клиента после смены сети. - MTU. Если мелкие запросы проходят, а крупные — нет, снижайте MTU на интерфейсе WireGuard у клиента и повторяйте тесты.
- Keepalive. Для клиентов за NAT/CGNAT проверьте, что
PersistentKeepaliveвыставлен и не слишком большой (25 — хорошая отправная точка). - DNS re-resolve. При смене IP сервера убедитесь, что клиенты пере‑резолвили домен. На Linux помогайте себе
wg setconfили перезапуском интерфейса.
Особенности мобильных клиентов
Официальные приложения на iOS/Android умеют «подхватывать» сетевые события и триггерить повторное рукопожатие. Но энергосбережение ОС может откладывать фоновые задачи. Если пользователи жалуются на «долгий выход из сна», попробуйте снизить PersistentKeepalive до 20–15, а также убедитесь, что приложению выданы права на работу в фоне и отключены жесткие оптимизации батареи.
Несколько аплинков на сервере
Если у сервера два провайдера и исходящий адрес может меняться, убедитесь, что:
- маскарад/маршрутизация обратного трафика идут через интерфейс, где сервер получил входящие пакеты по UDP 51820;
- политики фильтрации не меняют исходящий порт неожиданно;
- по возможности используйте стабильный публичный адрес и фиксированный
ListenPort.
Если требуются проксирование или балансировка UDP для WireGuard, посмотрите материал про балансировку TCP/UDP в Nginx Stream. Для межофисных тоннелей пригодится статья WireGuard site‑to‑site на VDS.
Частые вопросы
- Нужно ли ставить keepalive на обеих сторонах? Обычно нет. Достаточно на стороне клиента за NAT. Дублировать смысла мало, только увеличите фоновый трафик.
- Какое значение выбрать? Начинайте с 25 секунд, корректируйте по логам и отзывам пользователей.
- Что с MTU по умолчанию? Для Ethernet часто работает 1420. Если есть жалобы — снижайте до 1400 или 1380. В крайних случаях 1280.
- Почему сервер не видит клиента после смены сети? Клиент не отправил ни одного пакета (нет keepalive), блокируется UDP, или потерян маршрут/неверный MTU.
Чек‑лист внедрения роуминга WireGuard
- У клиента за NAT включен
PersistentKeepalive = 25. - На клиенте задан адекватный
MTU(стартуйте с 1420, затем корректируйте тестами). - Сервер слушает стабильный
ListenPort, проброшен на внешнем маршрутизаторе (если нужен). UDP не фильтруется. - В
AllowedIPsнет конфликтующих подсетей с локальными сетями клиента. Endpointзадан доменным именем, а клиенты умеют re‑resolve (при необходимости — скрипт/таймер сwg setconf).- Логи и
wg showмониторятся: отслеживаете «latest handshake», «transfer» и «endpoint» при сетевых сменах.
Настроив эти элементы, вы получите отказоустойчивый роуминг WireGuard‑клиентов без «магии»: сервер автоматически примет новый адрес клиента, NAT не успеет «забыть» соответствие благодаря PersistentKeepalive, а правильно подобранный MTU избавит от подвисаний на крупных ответах. В итоге мобильные пользователи перестанут «ронять» VPN при каждом переходе между сетями.


