VPN и MTU: проблема фрагментации и как подобрать значение
VPN подключается, значок горит зелёным, ping до сервера отвечает мгновенно — а сайт открывается наполовину, SSH виснет ровно в тот момент, когда вы выводите длинный список файлов, а копирование по SCP замирает на одном и том же файле. Это классическая картина проблемы с MTU: маленькие пакеты проходят без проблем, а крупные — теряются молча, без единой ошибки в логах. Разбираемся, откуда берётся это значение, почему VPN его портит и как подобрать правильное число вместо угадывания.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое MTU и при чём тут VPN
MTU (Maximum Transmission Unit) — это максимальный размер пакета, который может пройти через сетевой интерфейс за один раз. У обычного Ethernet-соединения это почти всегда 1500 байт — значение сложилось исторически и работает как умолчание почти везде: у вашего роутера, у сервера, у провайдера.
Проблема в том, что VPN не передаёт ваш трафик «как есть» — он заворачивает каждый пакет в дополнительный конверт: свои заголовки, шифрование, служебные данные протокола. У WireGuard это обычно около 60 байт накладных расходов, у OpenVPN — 40-60 в зависимости от режима. Если ваша система продолжает слать пакеты по 1500 байт внутрь туннеля, поверх которых VPN добавляет ещё 60, итоговый пакет на выходе — 1560 байт, а физический канал пропускает не больше 1500. Пакет нужно дробить (фрагментировать) или отбрасывать.
Именно здесь и прячется засада: у TCP-пакетов часто выставлен флаг DF — Don't Fragment, «не дробить», он экономит сетевому оборудованию работу по сборке фрагментов. Если такой пакет не помещается в MTU канала, маршрутизатор должен ответить ICMP-сообщением «Fragmentation Needed» — по этому сигналу отправитель узнаёт, что нужно уменьшить размер пакетов (механизм Path MTU Discovery, PMTUD). Но многие домашние роутеры, фаерволы и особенно сами VPN-туннели такие ICMP-сообщения по умолчанию блокируют. В итоге отправитель никогда не узнаёт, что пакет не дошёл — он просто пропадает в никуда. Это называют «чёрной дырой PMTUD»: соединение как бы есть, но крупные пакеты в него не помещаются, а сигнала об этом никто не подаёт.
Симптомы неправильного MTU: сайты не грузятся, SSH виснет
Именно из-за механизма фрагментации проблема с MTU выглядит очень характерно — и почти всегда сбивает с толку тех, кто впервые с ней сталкивается, потому что часть вещей продолжает работать нормально:
pingдо сервера и до интернета проходит без потерь. ICMP-пакеты по умолчанию маленькие (обычно 56-64 байта полезной нагрузки), они укладываются в любой MTU и никогда не сталкиваются с проблемой.- SSH подключается, показывает приглашение, но виснет на конкретных командах. Сама сессия и короткий обмен (логин, пароль или ключ) — это маленькие пакеты. А вот вывод команды
ls -laв большой директории,catдлинного файла или прокрутка выводаtop— это уже крупные пакеты, которые упираются в MTU и пропадают. - Сайт открывается наполовину. HTML-код страницы обычно небольшой и грузится нормально, а вот крупные картинки, шрифты или сама установка TLS-соединения (сертификаты часто крупнее 1400 байт) подвисает или обрывается по таймауту.
- SCP/rsync зависает на одном и том же файле, причём часто на одном и том же проценте — это тоже про упор в размер пакета, а не про сеть в целом.
- В браузере ошибка
ERR_CONNECTION_RESETилиSSL_ERROR_RX_RECORD_TOO_LONGна некоторых сайтах, но не на всех — потому что не все страницы генерируют пакеты, которые упираются в лимит.
Если же интернет через VPN не работает вообще — не открывается ничего, даже мелкие запросы — это, скорее всего, другая проблема: NAT, firewall или DNS, а не MTU. Разбор такого случая — в статье про WireGuard, который подключается, но не даёт выхода в интернет. Здесь же — именно частичная, «выборочная» проблема: маленькое работает, крупное нет.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверКак найти правильный MTU: ping -M do
Не нужно гадать между 1400, 1420 и 1450 — точное значение находится за пять минут одной командой. Ключ — флаг -M do, который заставляет ping выставлять тот самый флаг «не дробить» и честно сообщать, если пакет не прошёл, вместо того чтобы фрагментировать его самостоятельно.
На Linux и macOS команда выглядит так (на macOS вместо -M do используется -D):
# Linux
ping -M do -s 1472 8.8.8.8
# macOS
ping -D -s 1472 8.8.8.8
Число после -s — это размер полезной нагрузки ICMP без учёта заголовков IP (20 байт) и ICMP (8 байт). Поэтому -s 1472 фактически проверяет пакет размером 1500 байт целиком — стандартный MTU Ethernet. Если команда отвечает 64 bytes from ... — пакет такого размера проходит. Если видите Frag needed and DF set или sendto: Message too long (иногда просто зависание с последующим 100% packet loss) — пакет не прошёл, значение нужно уменьшать.
Дальше — обычный бинарный поиск. Уменьшайте -s вдвое от разницы, пока не найдёте максимальное проходящее значение:
ping -M do -s 1400 8.8.8.8 # прошло — пробуем больше
ping -M do -s 1450 8.8.8.8 # не прошло — пробуем между 1400 и 1450
ping -M do -s 1420 8.8.8.8 # прошло — пробуем между 1420 и 1450
ping -M do -s 1435 8.8.8.8 # и так далее, пока не найдёте точную границу
К найденному числу прибавьте 28 (заголовки IP + ICMP) — это и есть реальный MTU канала. Проверяйте команду именно из-под поднятого VPN-туннеля, если ищете MTU для трафика внутри него, и отдельно — на «чистом» интерфейсе без VPN. На Windows аналог — ping -f -l 1472 8.8.8.8, флаг -f соответствует «не дробить».
Правильный MTU для WireGuard
Если ping-тест на «чистом» интерфейсе (без VPN) показал полные 1500 байт — то есть провайдер и промежуточные сети не режут MTU — можно посчитать нужное значение для WireGuard напрямую по формуле, не гадая через туннель:
MTU туннеля = MTU физического интерфейса − overhead WireGuard
Overhead WireGuard для IPv4-инкапсуляции — 60 байт (20 IP + 8 UDP + 32 заголовок WireGuard), для IPv6-инкапсуляции — на 20 байт больше. При стандартном MTU 1500 это даёт распространённое рекомендуемое значение 1420 — оно же чаще всего стоит по умолчанию в готовых генераторах конфигов и достаточно консервативно, чтобы работать почти везде, включая мобильные сети с их дополнительными накладными расходами.
Задать MTU в конфиге клиента WireGuard просто — добавьте строку в секцию [Interface]:
[Interface]
PrivateKey = ....
Address = 10.0.0.2/24
DNS = 1.1.1.1
MTU = 1420
Если провайдер режет MTU сильнее (мобильный интернет, PPPoE с его 8 байтами оверхеда), уменьшайте значение шагами по 20-40, пока проблема не исчезнет — проверяйте тем же ping -M do, но уже через интерфейс wg0. Основную установку WireGuard мы разбирали в статье про установку и настройку WireGuard на VPS — MTU можно добавить в существующий конфиг без переустановки.
Правильный MTU для OpenVPN
У OpenVPN логика похожая, но есть три разных директивы, и путать их не стоит:
| Директива | Что делает | Когда использовать |
|---|---|---|
tun-mtu 1400 | Меняет реальный MTU виртуального интерфейса tun/tap | Когда нужно жёстко зафиксировать размер — должна совпадать на клиенте и сервере |
mssfix 1360 | Подрезает MSS только для TCP-соединений через туннель, не трогая сам интерфейс | Самый безопасный вариант «по умолчанию», решает 90% случаев |
fragment 1300 | Дробит слишком крупные UDP-пакеты силами самого OpenVPN | Крайняя мера, добавляет накладные расходы — использовать, если ничего другое не помогло |
Для большинства ситуаций достаточно mssfix — эта директива не меняет размер самого туннельного интерфейса, а лишь подменяет значение MSS (Maximum Segment Size) в заголовке TCP при установке соединения, так что приложение само не пытается отправить пакет крупнее, чем выдержит канал. Добавляется в конфиг клиента (файл .ovpn) одной строкой:
mssfix 1360
Если проблема касается и UDP-трафика тоже (например, вы гоняете через VPN что-то поверх UDP, а не только веб и SSH), mssfix не поможет — он работает только с TCP. В таком случае нужен tun-mtu, но его придётся синхронизировать на клиенте и сервере — расхождение значений само по себе создаёт новую проблему с фрагментацией. Общая установка OpenVPN разобрана в статье про установку и настройку OpenVPN на VPS, туда же можно добавить нужную директиву MTU при первичной настройке.
MSS clamping на сервере: почему это надёжнее ручной настройки MTU
Ручная правка MTU в конфиге клиента решает проблему только для этого конкретного устройства с этим конкретным конфигом. Если у вас десяток клиентов — телефон, ноутбук, роутер с VPN-клиентом — MTU придётся подгонять на каждом отдельно, и при смене сети (например, с домашнего Wi-Fi на мобильный интернет) подобранное значение снова может не подойти.
Более надёжный подход — не трогать MTU вообще, а заставить сервер автоматически подрезать MSS у любого проходящего TCP-соединения под фактический размер туннеля, независимо от настроек клиента. Это и есть MSS clamping, настраивается одним правилом iptables на самом VPN-сервере:
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
Правило перехватывает момент установки TCP-соединения (пакет с флагом SYN) и переписывает в нём заявленный MSS так, чтобы итоговый пакет гарантированно помещался в MTU исходящего интерфейса. Клиент при этом ничего не знает и не должен ничего менять в своём конфиге — он с самого начала договаривается о правильном размере сегмента. Это снимает всю проблему с чёрными дырами PMTUD, потому что клиенту вообще не нужно узнавать об ограничении через ICMP — сервер сообщает нужный размер прямо в момент рукопожатия.
Правило стоит прописать в PostUp конфига WireGuard (/etc/wireguard/wg0.conf) рядом со строкой MASQUERADE, чтобы оно применялось при каждом поднятии туннеля:
PostUp = iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostDown = iptables -t mangle -D FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Для OpenVPN аналогичное правило добавляется в firewall сервера отдельной строкой, без изменений в самом конфиге OpenVPN. Стоит понимать ограничение: clamping работает только для TCP — если у вас проблемы с фрагментацией на UDP-трафике внутри туннеля (например, потоковое видео или игры поверх VPN), это правило не поможет, и там нужен именно tun-mtu или ручной подбор MTU клиента из предыдущих разделов.
Арендуйте сервер под свои задачи!
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Как понять, что дело именно в MTU, а не в чём-то ещё?
Главный признак — избирательность: маленькие запросы (ping, начало SSH-сессии, короткие HTTP-ответы) работают, а крупные (файлы, картинки, вывод длинных команд) зависают или обрываются. Если не работает вообще всё, включая ping до сервера, — это не MTU, а более базовая проблема с маршрутизацией или firewall.
Можно ли просто поставить MTU поменьше, например 1280, и не разбираться?
Можно, и это сработает почти везде — 1280 это минимальный гарантированный MTU для IPv6, его пропускает практически любая сеть. Недостаток — избыточно маленькие пакеты чуть увеличивают накладные расходы на каждый мегабайт трафика, особенно заметно на медленных или загруженных каналах. Точный подбор через ping -M do даёт максимум производительности без потери надёжности.
MSS clamping и MTU клиента — нужно ли и то, и другое одновременно?
Обычно достаточно одного из них для TCP-трафика. MSS clamping на сервере предпочтительнее, потому что не требует настройки на каждом клиенте и переживает смену сети на стороне пользователя. MTU на клиенте остаётся нужен для UDP-based приложений и как более универсальное решение, если сервер не под вашим контролем.
После смены MTU нужно ли перезапускать туннель?
Да, для WireGuard — wg-quick down wg0 и wg-quick up wg0 после правки конфига. Для OpenVPN директивы mssfix, tun-mtu и fragment применяются только при новом подключении, разорвите и переподключите сессию клиента.
Проблема появилась не сразу, а после смены сети (например, переехали на мобильный интернет)?
Это типичный случай: у разных сетей разный реальный MTU — мобильные операторы часто режут его сильнее, чем домашний провод. Значение, подобранное для одной сети, может не подойти для другой — отсюда и преимущество MSS clamping на сервере, которое не завязано на конкретную сеть клиента.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →