Снижение скорости при работе через VPN — не баг конкретного клиента, а следствие нескольких механизмов, которые накладываются друг на друга. Основные виновники: превышение MTU и фрагментация пакетов, ретрансмиссии из-за TCP поверх TCP, криптографические накладные расходы и неоптимальная маршрутизация. Ниже — разбор каждого фактора и конкретные шаги диагностики.
Каждый VPN-протокол оборачивает исходный IP-пакет в дополнительный заголовок. Стандартный MTU Ethernet — 1500 байт. Когда туннель добавляет свои заголовки, полезная нагрузка должна уменьшиться, иначе пакет не пройдёт.
Структура накладных расходов для типичных протоколов:
WireGuard инкапсулирует IP-пакеты поверх UDP. Суммарный overhead для IPv4 составляет 56 байт: 20 (IP) + 8 (UDP) + 28 (заголовок WireGuard-пакета: 4 байта типа, 8 байт счётчика, 16 байт тега аутентификации Poly1305). Теоретический максимум полезной нагрузки — 1444 байта. Однако стандартный MTU интерфейса
Если клиент отправляет пакет размером 1500 байт через туннель с MTU 1420, происходит одно из двух:
На Linux используется
Здесь
На Windows аналогичная проверка:
Флаг
Найдите максимальный размер данных, который проходит без фрагментации. Формула:
28 байт — это IP-заголовок (20) + ICMP-заголовок (8). Для WireGuard результат обычно составляет 1420, для OpenVPN over UDP — около 1400–1440 в зависимости от шифра.
Убедитесь, что MTU туннельного интерфейса на сервере совпадает с клиентским:
В выводе будет строка вида
PMTUD (Path MTU Discovery) зависит от ICMP-сообщений типа 3, код 4 (Fragmentation Needed). Если промежуточный маршрутизатор или файрвол блокирует ICMP, клиент не узнает о необходимости уменьшить размер пакета. Проверьте:
Если трассировка обрывается на определённом хопе без сообщения о фрагментации — ICMP фильтруется.
Когда пакет превышает MTU следующего звена и бит DF не установлен, маршрутизатор разбивает его на фрагменты. Каждый фрагмент:
Для VPN это особенно критично, потому что туннель уже добавил свои заголовки. Пакет, который был бы целым без туннеля, после инкапсуляции превышает MTU физического канала и фрагментируется.
Признаки фрагментации в выводе
Этот фильтр показывает пакеты с ненулевым offset фрагментации. Если такие пакеты появляются в большом количестве — MTU настроен неверно.
При фрагментации пакета размером 1500 байт на два фрагмента (например, 1480 + 20 байт данных) потеря любого из них приводит к полной потере исходного пакета. На канале с потерей 1% вероятность потери хотя бы одного фрагмента из двух составляет примерно 2%, из трёх — около 3%. Эффективная потеря растёт линейно с числом фрагментов, а TCP интерпретирует это как перегрузку и снижает окно.
Когда VPN-туннель работает поверх TCP (например, OpenVPN в режиме
Результат: при потере даже 1–2% пакетов пропускная способность TCP-туннеля падает в разы сильнее, чем UDP-туннеля при тех же условиях.
WireGuard использует только UDP, что исключает эту проблему. OpenVPN по умолчанию также рекомендует UDP. TCP-режим OpenVPN оправдан только когда UDP полностью заблокирован (корпоративные файрволы, цензура).
Сравните скорость через один и тот же сервер в режимах UDP и TCP. Если разница кратная (в 3–10 раз при нестабильном канале) — проблема именно в TCP meltdown.
Дополнительно можно посмотреть ретрансмиссии:
Большое число ретрансмиссий на туннельном интерфейсе подтверждает проблему.
Некоторые реализации (например, OpenVPN с
Шифрование и аутентификация каждого пакета требуют CPU. На современных процессорах с аппаратным ускорением (AES-NI, AVX2) overhead минимален — единицы процентов. На старых CPU или ARM-устройствах без аппаратного ускорения шифрование может стать узким местом.
WireGuard использует ChaCha20-Poly1305, который эффективно работает даже без аппаратного ускорения AES, что делает его быстрым на широком спектре устройств.
Проверка загрузки CPU во время активной передачи:
Если
VPN-сервер может находиться географически далеко или за несколькими промежуточными хопами. Каждый хоп добавляет задержку. Проверьте RTT до сервера без туннеля:
Если базовый RTT высокий (>100 мс), туннель не сможет обеспечить низкую задержку независимо от настроек MTU.
Если VPN-сервер обслуживает много клиентов одновременно, пропускная способность делится между ними. Это особенно актуально для публичных VPN-сервисов. Проверка: сравните скорость в часы пик и в непиковое время.
Некоторые маршрутизаторы, NAT-устройства или облачные балансировщики могут иметь MTU меньше 1500 (например, PPPoE-соединения с MTU 1492, GRE-туннели с MTU 1476). В этом случае даже правильно настроенный MTU туннеля 1420 может оказаться слишком большим.
Типичные значения MTU на различных уровнях:
Если между клиентом и VPN-сервером есть PPPoE-звено, максимальный размер пакета снижается до 1492, и туннельный MTU нужно уменьшить ещё на 8 байт.
MTU задаётся в конфигурации интерфейса или при создании:
Или в конфигурационном файле (зависит от дистрибутива и менеджера сетей). Для systemd-networkd:
В конфигурации клиента и сервера:
Значение подбирается по результатам диагностики из раздела выше.
Если PMTUD не работает из-за блокировки ICMP, можно принудительно ограничить MSS для TCP-соединений, проходящих через туннель:
Это заставляет TCP-соединения использовать меньший размер сегмента, избегая фрагментации. Значение MSS = MTU туннеля − 40 (IP + TCP заголовки). Для MTU 1420: MSS = 1380.
Команда изменяет правила файрвола. Перед применением убедитесь, что понимаете текущую политику iptables.
Если после всех проверок скорость остаётся низкой, а MTU, фрагментация и TCP meltdown исключены — проблема, скорее всего, на стороне сервера (перегрузка, ограничение полосы) или в канале между вами и сервером (потери, джиттер). В этом случае стоит попробовать другой сервер или другого провайдера.
MTU и инкапсуляция: где теряются байты
Каждый VPN-протокол оборачивает исходный IP-пакет в дополнительный заголовок. Стандартный MTU Ethernet — 1500 байт. Когда туннель добавляет свои заголовки, полезная нагрузка должна уменьшиться, иначе пакет не пройдёт.
Структура накладных расходов для типичных протоколов:
| Протокол | Внешний заголовок | Внутренний overhead | Рекомендуемый MTU туннеля |
|---|---|---|---|
| WireGuard (UDP) | IP (20) + UDP (8) | 28 (4 type + 8 counter + 16 auth tag) | 1420 |
| OpenVPN (UDP) | IP (20) + UDP (8) | ~20–40 (зависит от шифра) | 1400–1440 |
| OpenVPN (TCP) | IP (20) + TCP (20) | ~20–40 | 1360–1400 |
| IPsec (ESP, transport) | IP (20) + ESP (~20–24) | 12–16 (IV + ICV) | ~1400–1420 |
WireGuard инкапсулирует IP-пакеты поверх UDP. Суммарный overhead для IPv4 составляет 56 байт: 20 (IP) + 8 (UDP) + 28 (заголовок WireGuard-пакета: 4 байта типа, 8 байт счётчика, 16 байт тега аутентификации Poly1305). Теоретический максимум полезной нагрузки — 1444 байта. Однако стандартный MTU интерфейса
wg0 установлен в 1420 байт — это консервативное значение с запасом на IPv6 (где IP-заголовок занимает 40 байт вместо 20) и возможную дополнительную инкапсуляцию.Если клиент отправляет пакет размером 1500 байт через туннель с MTU 1420, происходит одно из двух:
- Фрагментация — пакет разбивается на несколько фрагментов. Каждый фрагмент несёт свой IP-заголовок, что увеличивает общий объём трафика.
- Отбрасывание — если установлен бит Don't Fragment (DF), пакет отбрасывается, и отправитель получает ICMP-сообщение «Fragmentation Needed». Если ICMP заблокирован файрволом, отправитель не узнает о проблеме и будет повторять попытку.
Диагностика MTU: пошаговая проверка
Шаг 1. Определение максимального размера пакета без фрагментации
На Linux используется
ping с флагом DF и указанием размера полезной нагрузки:
Bash:
ping -M do -s 1400 -c 5 10.0.0.1
Здесь
10.0.0.1 — адрес VPN-сервера или удалённого хоста за туннелем. Параметр -s задаёт размер данных (без учёта 8 байт ICMP-заголовка и 20 байт IP-заголовка). Если пакет проходит — увеличивайте размер. Если получаете ошибку message too long — уменьшайте.На Windows аналогичная проверка:
Код:
ping -f -l 1400 10.0.0.1
Флаг
-f устанавливает DF, -l задаёт размер данных.Шаг 2. Вычисление оптимального MTU
Найдите максимальный размер данных, который проходит без фрагментации. Формула:
Код:
MTU_туннеля = максимальный_размер_данных + 28
28 байт — это IP-заголовок (20) + ICMP-заголовок (8). Для WireGuard результат обычно составляет 1420, для OpenVPN over UDP — около 1400–1440 в зависимости от шифра.
Шаг 3. Проверка на стороне сервера
Убедитесь, что MTU туннельного интерфейса на сервере совпадает с клиентским:
Bash:
ip link show wg0
В выводе будет строка вида
mtu 1420. Если значение отличается от клиентского, пакеты будут фрагментироваться или отбрасываться на одном из концов.Шаг 4. Проверка прохождения ICMP
PMTUD (Path MTU Discovery) зависит от ICMP-сообщений типа 3, код 4 (Fragmentation Needed). Если промежуточный маршрутизатор или файрвол блокирует ICMP, клиент не узнает о необходимости уменьшить размер пакета. Проверьте:
Bash:
traceroute -M do -s 1472 10.0.0.1
Если трассировка обрывается на определённом хопе без сообщения о фрагментации — ICMP фильтруется.
Фрагментация IP: скрытый убийца производительности
Когда пакет превышает MTU следующего звена и бит DF не установлен, маршрутизатор разбивает его на фрагменты. Каждый фрагмент:
- Несёт полный IP-заголовок (20 байт), что увеличивает общий объём.
- Обрабатывается независимо: потеря одного фрагмента приводит к отбрасыванию всего исходного пакета.
- Требует сборки на стороне получателя, что добавляет задержку и нагрузку на CPU.
Для VPN это особенно критично, потому что туннель уже добавил свои заголовки. Пакет, который был бы целым без туннеля, после инкапсуляции превышает MTU физического канала и фрагментируется.
Признаки фрагментации в выводе
tcpdump:
Bash:
tcpdump -i eth0 -nn 'ip[6:2] & 0x3fff != 0'
Этот фильтр показывает пакеты с ненулевым offset фрагментации. Если такие пакеты появляются в большом количестве — MTU настроен неверно.
Почему потеря одного фрагмента обходится дорого
При фрагментации пакета размером 1500 байт на два фрагмента (например, 1480 + 20 байт данных) потеря любого из них приводит к полной потере исходного пакета. На канале с потерей 1% вероятность потери хотя бы одного фрагмента из двух составляет примерно 2%, из трёх — около 3%. Эффективная потеря растёт линейно с числом фрагментов, а TCP интерпретирует это как перегрузку и снижает окно.
TCP поверх TCP: почему OpenVPN на TCP тормозит сильнее
Когда VPN-туннель работает поверх TCP (например, OpenVPN в режиме
--proto tcp), возникает проблема, известная как TCP meltdown:- Приложение отправляет данные через туннель.
- Туннельный TCP-сегмент теряется или приходит с задержкой.
- TCP туннеля запускает ретрансмиссию и уменьшает congestion window.
- Внутренний TCP приложения тоже обнаруживает потерю (таймаут) и уменьшает своё окно.
- Два уровня TCP конкурируют за восстановление, многократно снижая пропускную способность.
Результат: при потере даже 1–2% пакетов пропускная способность TCP-туннеля падает в разы сильнее, чем UDP-туннеля при тех же условиях.
WireGuard использует только UDP, что исключает эту проблему. OpenVPN по умолчанию также рекомендует UDP. TCP-режим OpenVPN оправдан только когда UDP полностью заблокирован (корпоративные файрволы, цензура).
Как проверить, что проблема в TCP-туннеле
Сравните скорость через один и тот же сервер в режимах UDP и TCP. Если разница кратная (в 3–10 раз при нестабильном канале) — проблема именно в TCP meltdown.
Дополнительно можно посмотреть ретрансмиссии:
Bash:
ss -ti | grep retrans
Большое число ретрансмиссий на туннельном интерфейсе подтверждает проблему.
Альтернатива: TCP только для управляющего канала
Некоторые реализации (например, OpenVPN с
--proto tcp на управляющем канале и UDP для данных) позволяют обойти цензуру без полного TCP meltdown. Если UDP заблокирован, но есть возможность использовать TLS-туннель (например, через stunnel или obfsproxy), это предпочтительнее чистого TCP-режима.Другие факторы потери скорости
Криптографические накладные расходы
Шифрование и аутентификация каждого пакета требуют CPU. На современных процессорах с аппаратным ускорением (AES-NI, AVX2) overhead минимален — единицы процентов. На старых CPU или ARM-устройствах без аппаратного ускорения шифрование может стать узким местом.
WireGuard использует ChaCha20-Poly1305, который эффективно работает даже без аппаратного ускорения AES, что делает его быстрым на широком спектре устройств.
Проверка загрузки CPU во время активной передачи:
Bash:
top -bn1 | grep -E 'softirq|ksoftirqd'
Если
ksoftirqd потребляет значительную долю CPU при активной передаче через туннель — криптография или сетевой стек не справляются.Неоптимальная маршрутизация
VPN-сервер может находиться географически далеко или за несколькими промежуточными хопами. Каждый хоп добавляет задержку. Проверьте RTT до сервера без туннеля:
Bash:
ping -c 20 vpn-server.example.com
Если базовый RTT высокий (>100 мс), туннель не сможет обеспечить низкую задержку независимо от настроек MTU.
Ограничения сервера
Если VPN-сервер обслуживает много клиентов одновременно, пропускная способность делится между ними. Это особенно актуально для публичных VPN-сервисов. Проверка: сравните скорость в часы пик и в непиковое время.
MTU на промежуточных устройствах
Некоторые маршрутизаторы, NAT-устройства или облачные балансировщики могут иметь MTU меньше 1500 (например, PPPoE-соединения с MTU 1492, GRE-туннели с MTU 1476). В этом случае даже правильно настроенный MTU туннеля 1420 может оказаться слишком большим.
Типичные значения MTU на различных уровнях:
| Тип соединения | MTU |
|---|---|
| Ethernet | 1500 |
| PPPoE | 1492 |
| GRE-туннель | 1476 |
| Jumbo Frame | 9000 |
Если между клиентом и VPN-сервером есть PPPoE-звено, максимальный размер пакета снижается до 1492, и туннельный MTU нужно уменьшить ещё на 8 байт.
Настройка MTU: практические команды
WireGuard
MTU задаётся в конфигурации интерфейса или при создании:
Bash:
ip link set wg0 mtu 1420
Или в конфигурационном файле (зависит от дистрибутива и менеджера сетей). Для systemd-networkd:
INI:
[WireGuard]
MTUBytes=1420
OpenVPN
В конфигурации клиента и сервера:
Код:
tun-mtu 1400
Значение подбирается по результатам диагностики из раздела выше.
Принудительное снижение MSS (TCP Clamping)
Если PMTUD не работает из-за блокировки ICMP, можно принудительно ограничить MSS для TCP-соединений, проходящих через туннель:
Bash:
iptables -t mangle -A FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1380
Это заставляет TCP-соединения использовать меньший размер сегмента, избегая фрагментации. Значение MSS = MTU туннеля − 40 (IP + TCP заголовки). Для MTU 1420: MSS = 1380.
Команда изменяет правила файрвола. Перед применением убедитесь, что понимаете текущую политику iptables.
Чек-лист диагностики
| Шаг | Действие | Ожидаемый результат |
|---|---|---|
| 1 | ping -M do -s 1400 <server> | Пакеты проходят без ошибок |
| 2 | Увеличивать -s до появления ошибки | Определить максимальный размер |
| 3 | ip link show <tunnel_if> | MTU совпадает на клиенте и сервере |
| 4 | tcpdump с фильтром фрагментов | Фрагментация отсутствует |
| 5 | traceroute -M do | ICMP Fragmentation Needed не блокируется |
| 6 | Сравнить UDP и TCP режимы | UDP не даёт кратного падения |
| 7 | ss -ti на туннельном интерфейсе | Ретрансмиссии минимальны |
| 8 | top / mpstat во время нагрузки | CPU не перегружен softirq |
| 9 | ping до сервера без туннеля | Базовый RTT приемлемый |
Если после всех проверок скорость остаётся низкой, а MTU, фрагментация и TCP meltdown исключены — проблема, скорее всего, на стороне сервера (перегрузка, ограничение полосы) или в канале между вами и сервером (потери, джиттер). В этом случае стоит попробовать другой сервер или другого провайдера.
