Инкапсуляция и MTU: почему VPN поверх IPv6-прокси режет скорость и как подобрать MSS
Содержание
- Физика процесса
- Что происходит с WireGuard поверх IPv6
- Подбор MSS вручную
- Практический тест
- Особенности IPv6-прокси
- Настройка на клиенте
- Таблица типичных значений
- Как понять, что проблема именно в MTU
- Автоматическое определение MTU
- !/bin/bash
- Влияние на реальные приложения
- Настройка на сервере
- MSS настраивается через iptables, не в конфиге nginx
- Частые ошибки
- Проверка скорости после настройки
- Резюме
Физика процесса
Пакет не может летать по сети сам по себе. У него есть рамки. Стандартный Ethernet-кадр — 1518 байт. Из них 14 байт — заголовок, 4 — контрольная сумма. Остаётся 1500 байт на IP-пакет. Это MTU. Всё, что больше, режется на фрагменты.
Теперь представьте: вы поднимаете VPN-туннель. Поверх IPv4-пакета ложится ещё один заголовок — GRE, ESP или WireGuard. Размер пакета не меняется, он просто перестаёт влезать. Отсюда и боль.
Что происходит с WireGuard поверх IPv6
WireGuard — это UDP-инкапсуляция. Поверх IPv6-пакета добавляется заголовок UDP (8 байт) и заголовок WireGuard (32 байта). Плюс сам IPv6-заголовок — 40 байт вместо 20 у IPv4. Итого дополнительные 60 байт на каждый пакет.
Возьмём стандартный MTU 1500. Внутренний пакет должен быть не больше 1440 байт. Если он больше — фрагментация. А фрагментация убивает производительность: каждый фрагмент получает свой IP-заголовок, растёт нагрузка на процессор, возрастает вероятность потерь.
Проверить текущий MTU на Linux можно так:
```bash
ip link show
```
Ищем строку с `mtu`. Для WireGuard-интерфейса обычно стоит 1420. Это значение взято не с потолка — оно учитывает все накладные расходы.
Подбор MSS вручную
MSS — максимальный размер сегмента TCP. Он на 40 байт меньше MTU (20 байт IP + 20 байт TCP). Если MSS не настроен, TCP договаривается о нём при установке соединения. Но в туннеле этот механизм не работает — внутренние пакеты не знают о внешнем заголовке.
Решение — принудительно выставить MSS на интерфейсе туннеля:
```bash
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
```
Для IPv6:
```bash
ip6tables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
```
Почему 1360? Считаем: 1500 (MTU) − 60 (IPv6 + UDP + WireGuard) − 40 (TCP/IP заголовки внутри) = 1400. Но лучше взять с запасом. 1360 — безопасное значение для большинства туннелей.
Практический тест
Проверить, режется ли скорость из-за MTU, просто. Запустите ping с разными размерами пакета:
```bash
ping -M do -s 1472 8.8.8.8
```
Флаг `-M do` запрещает фрагментацию. Если пакет не проходит — MTU меньше. Уменьшайте размер, пока не начнёт отвечать. Разница между 1472 и фактическим размером — ваши накладные расходы.
Пример из жизни: сервер на nginx 1.24 с настроенным MTU 1500 отдавал статику со скоростью 45 Мбит/с через WireGuard поверх IPv6. После установки MSS 1360 скорость выросла до 180 Мбит/с. Причина — TCP пакеты резались на уровне ядра, каждое соединение требовало повторной передачи.
Особенности IPv6-прокси
IPv6-прокси, вроде lexic.ml, добавляют ещё один слой инкапсуляции. Пакет идёт от вашего сервера к прокси, оттуда — в интернет. Если прокси сам использует туннель — расходы суммируются.
Типичная цепочка: ваш сервер → WireGuard → IPv6-прокси → интернет. Каждый переход добавляет заголовки. В такой схеме MTU 1500 превращается в 1380 или даже меньше.
Настройка на клиенте
Если вы используете WireGuard на Windows, MTU настраивается в конфигурационном файле:
```ini
[Interface]
PrivateKey = ...
Address = 10.0.0.2/24
MTU = 1380
```
Для macOS:
```bash
sudo ifconfig utun4 mtu 1380
```
Для Android — в приложении WireGuard, пункт "MTU" в настройках туннеля.
Таблица типичных значений
| Туннель | Накладные расходы | Рекомендуемый MTU |
|---------|------------------|-------------------|
| WireGuard IPv4 | 60 байт | 1440 |
| WireGuard IPv6 | 80 байт | 1420 |
| OpenVPN UDP IPv4 | 60 байт | 1440 |
| OpenVPN TCP IPv4 | 80 байт | 1420 |
| GRE IPv4 | 24 байта | 1476 |
| IPsec ESP IPv4 | 52 байта | 1448 |
Цифры примерные, зависят от настроек шифрования и алгоритмов.
Как понять, что проблема именно в MTU
Симптомы: скорость падает при передаче больших файлов, но нормальная при мелких запросах. Сайты открываются, но картинки грузятся медленно. SSH работает, но scp зависает.
Проверьте статистику пакетов:
```bash
ip -s link show wg0
```
Если видите ошибки `tx errors` или `rx errors` — пакеты теряются. Сравните с обычным интерфейсом.
Автоматическое определение MTU
Вместо ручной настройки можно использовать path MTU discovery. Но в туннелях он часто ломается — ICMP-сообщения "Fragmentation Needed" не доходят до отправителя. Поэтому и приходится выставлять MSS вручную.
Есть скрипты, которые автоматически подбирают MTU:
```bash
!/bin/bash
for size in 1500 1492 1480 1472 1460 1440 1420 1400 1380 1360; do
if ping -M do -s \$((size - 28)) -c 1 -W 1 8.8.8.8 > /dev/null 2>&1; then
echo "MTU \$size works"
else
echo "MTU \$size fails"
fi
done
```
Но помните: значение, которое работает для 8.8.8.8, может не работать для других хостов. Лучше настроить MSS — он применяется ко всем соединениям.
Влияние на реальные приложения
HTTP/2 и QUIC ведут себя по-разному при фрагментации. QUIC — это UDP, он не использует MSS. Его пакеты фрагментируются на уровне IP, что приводит к потере производительности. HTTP/2 использует TCP, поэтому настройка MSS помогает.
Пример: сайт на HTTP/2 с включённым QUIC показывал скорость 120 Мбит/с без туннеля и 30 Мбит/с через WireGuard. После настройки MSS скорость выросла до 95 Мбит/с. QUIC остался медленным — пришлось отключить его на сервере.
Настройка на сервере
Для nginx можно выставить MSS на уровне конфигурации:
```nginx
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
tcp_nodelay on;
MSS настраивается через iptables, не в конфиге nginx
}
```
Основная настройка — в iptables. Не забывайте про IPv6:
```bash
ip6tables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
```
Эта команда автоматически подстраивает MSS под PMTU. Но работает только если PMTU корректно определяется.
Частые ошибки
Многие ставят MTU 1400 на WireGuard-интерфейс и забывают про MSS. Пакеты проходят, но TCP-сегменты остаются большими. Результат — фрагментация на уровне IP, потеря производительности.
Другая ошибка — настройка MTU на внешнем интерфейсе. Если у вас PPPoE-соединение с MTU 1492, туннель поверх него должен учитывать это. Внутренний MTU туннеля = 1492 − накладные расходы.
Проверка скорости после настройки
Используйте iperf3 для точного замера:
```bash
iperf3 -c server -t 30 -P 4
```
Сравните результаты до и после настройки MSS. Разница обычно значительная — от 30% до 200% в зависимости от типа трафика.
Резюме
MTU и MSS — это не абстрактные цифры, а реальные ограничения. Игнорируете их — получаете потери пакетов, ретрамиссии и низкую скорость. Правильная настройка занимает пять минут, а экономит часы отладки. Начните с проверки текущего MTU, затем выставите MSS с запасом. И не забывайте про IPv6 — там накладные расходы больше.