Почему Tailscale работает медленно: прямая связь и relay
Скорость Tailscale падает из-за relay-соединений. Используйте команды tailscale status и tailscale netcheck для диагностики. Исправьте блокировки UDP и NAT на VPS.
Почему Tailscale работает медленно: ретрансляция вместо прямого соединения
Tailscale работает медленно при использовании ретрансляции (relay) и достигает скорости канала при прямом соединении. Прямое соединение передает зашифрованные пакеты WireGuard напрямую между машинами, поэтому скорость ограничена только пропускной способностью интернет-каналов обоих узлов. Ретранслируемое соединение сначала отправляет каждый пакет через третью машину, поэтому оно наследует задержки этого узла и доступную долю его пропускной способности. На странице производительности Tailscale это сформулировано одной фразой: «Прямые соединения почти всегда обеспечивают меньшую задержку и более высокую пропускную способность».
Внутри вашего приложения разница никак не отображается. Копирование файлов просто идет медленно, а SSH-сессия работает с задержками. Поэтому первая задача — определить тип текущего соединения. Две команды позволяют сделать это менее чем за минуту, а все последующие действия направлены на устранение причин. Стоит заранее понимать устройство системы, так как координационный сервер и плоскость передачи данных WireGuard — это отдельные системы, и только плоскость передачи данных пересылает ваши байты.
Две команды для определения прямого или ретранслируемого соединения
Отправьте немного трафика узлу, прежде чем проводить измерения. Tailscale выстраивает путь по запросу, поэтому для узла, с которым вы сегодня не общались, соединение могло быть ещё не согласовано, и вы получите устаревшие данные. Достаточно одного ping или одного curl на tailnet-адрес узла.
tailscale statusОтвет находится в конце строки каждого узла.
100.113.160.82 device-a tagged-devices linux active; offers exit node; direct 203.0.113.9:41641
100.104.93.78 device-b you@ android active; relay "tor"direct, за которым следует адрес и порт, означает, что пакеты идут напрямую по этому адресу. relay "tor" указывает на DERP-сервер (designated encrypted relay for packets) — это один из ретрансляторов Tailscale, через который проходят все пакеты к данному узлу. Третье значение, peer-relay, рассматривается в следующем разделе.
tailscale ping device-bИсправное соединение сначала устанавливается как ретранслируемое, а затем переключается. Первые пакеты проходят через ближайший DERP-сервер, пока машины договариваются, после чего путь меняется прямо у вас на глазах:
pong from device-b (100.113.160.82) via DERP(tor) in 51ms
pong from device-b (100.113.160.82) via DERP(tor) in 48ms
pong from device-b (100.113.160.82) via 203.0.113.9:41641 in 35msВыполнение останавливается, так как --until-direct по умолчанию имеет значение true. Соединение, которое не может стать прямым, выглядит иначе и заканчивается предложением, а не pong-ответом:
pong from device-b (100.104.93.78) via DERP(tor) in 53ms
pong from device-b (100.104.93.78) via DERP(tor) in 60ms
direct connection not establishedПоследняя строка — это и есть результат. Она означает, что Tailscale отправил все запланированные зонды, но не смог найти прямой путь. Чтобы продолжать наблюдение за ретранслируемым путем, вместо остановки на первом прямом, запустите tailscale ping --until-direct=false -c 20 device-b и оцените разброс задержки. Ретранслируемый путь обычно показывает как более высокие значения, так и большую вариативность, поскольку он состоит из двух интернет-каналов, соединенных на машине, которую вы не контролируете.
Что означает peer-relay в выводе tailscale status?
Peer-relay — это узел в вашей сети tailnet, который перенаправляет трафик для других участников, если прямое соединение невозможно. Он ожидает запросы на выбранном вами UDP-порту, и демон использует его в приоритете перед DERP. tailscale status помечает такое соединение как peer-relay, а tailscale ping выводит адрес ретранслятора:
pong from device-b (100.97.143.93) via peer-relay(203.0.113.42:40000:vni:1) in 4ms
direct connection not establishedОбратите внимание: это всё ещё не прямое соединение, поэтому результат работы по-прежнему завершается direct connection not established. Изменился лишь узел, выполняющий ретрансляцию. VPS с публичным IP-адресом и широким каналом связи гораздо лучше подходит для передачи вашего трафика, чем общий узел DERP, поэтому это важно для всех, кто арендует сервер. Включите эту функцию на машине с доступным публичным адресом:
sudo tailscale set --relay-server-port=40000Порт 0 выбирает случайный свободный порт, а пустая строка отключает сервер ретрансляции. Затем предоставьте клиентским устройствам разрешение на его использование с помощью возможности tailscale.com/cap/relay в файле политики вашей сети tailnet:
{
"grants": [
{
"src": ["tag:us-east-vpc"],
"dst": ["tag:us-east-relays"],
"app": {
"tailscale.com/cap/relay": []
}
}
]
}И устройство-ретранслятор, и клиентские устройства должны использовать Tailscale версии 1.86 или новее, поэтому проверьте версию с помощью tailscale version на каждом из них, прежде чем тратить время на настройку файла политики. Порядок попыток соединения демоном стоит запомнить. Сначала он пытается установить прямое соединение. Если это не удаётся, он ищет доступный peer-relay. Если таковых нет, он переключается на DERP. DERP никогда не исключается полностью, так как именно через этот канал устройства изначально договариваются о соединении.
Причина 1: исходящий файрвол, блокирующий UDP
В документации Tailscale указаны две причины, по которым соединение остается в режиме ретрансляции, и первая из них — блокировка UDP. Запросите состояние напрямую у узла:
tailscale netcheckОтчет здесь сокращен, и верхнее поле определяет всё:
Report:
* UDP: true
* IPv4: yes, 203.0.113.9:41641
* IPv6: no
* MappingVariesByDestIP: false
* PortMapping:
* Nearest DERP: DallasUDP: false — это исчерпывающий ответ, если вы видите его в выводе. Узел не может отправить UDP-пакет на серверы проверки Tailscale, поэтому прямой путь не формируется, и демон переключается на DERP через TCP-порт 443. Именно из-за этого резервного пути узел выглядит полностью исправным: он подключен, доступен, а все данные передаются через ретранслятор.
Документированы два исходящих правила. «Разрешите внутренним устройствам инициировать UDP-трафик из :41641 в *:*» — это сам трафик WireGuard, и «Разрешите внутренним устройствам инициировать UDP-трафик на *:3478» — это STUN (session traversal utilities for NAT), протокол, который узел использует для определения своего публичного адреса и порта. Используйте подстановочные знаки (wildcards) для адресов назначения. Tailscale со временем добавляет новые серверы ретрансляции, и список адресов, составленный вручную, устареет в течение года.
На арендованном сервере типичной причиной является строгая политика исходящего трафика — либо унаследованная в составе защищенного образа ОС, либо применяемая провайдером на вышестоящем уровне. Сначала проверьте политику по умолчанию для исходящих соединений:
sudo ufw status verbose
sudo nft list rulesetDefault: deny (incoming), allow (outgoing) — это нормальное состояние, проблема не в этом. Политика по умолчанию deny с коротким списком разрешенных портов (TCP 443 и DNS) — это именно та конфигурация, из-за которой сервер будет постоянно использовать ретрансляцию, так как путь DERP через TCP 443 проходит через это «окно», а прямой путь — нет. Место, где фактически прописаны эти правила, зависит от того, использует ли система iptables или nftables, и редактирование не того инструмента — частая причина отсутствия изменений.
Входящие соединения также важны, так как VPS имеет публичный IP-адрес и может выступать в роли более доступной стороны при установке соединения. Если файрвол разрешает входящий UDP-трафик на порту, который использует tailscaled, узлы за сложными домашними роутерами смогут подключиться к нему без дополнительных ухищрений. Узнайте порт, который используется в данный момент:
sudo ss -lunp | grep tailscaled
sudo ufw allow 41641/udp41641 — это стандартный статический порт. В tailnet с включенной настройкой randomizeClientPort клиенты выбирают случайный порт; в этом случае возьмите реальное число из вывода ss, а не из этой страницы. Затем проверьте панель управления вашего провайдера. Большинство хостинг-провайдеров используют сетевой файрвол, отдельный от того, что работает внутри сервера, и правило, добавленное вами через ufw, никак на него не влияет.
Причина 2: жесткий NAT на одном или обоих концах
Вторая задокументированная причина — жесткий NAT. NAT (network address translation) — это процесс, при котором маршрутизатор заменяет ваш частный адрес на публичный. «Дружелюбный» маршрутизатор сохраняет один и тот же публичный порт для конкретного внутреннего сокета независимо от того, с кем вы общаетесь; это называется endpoint independent mapping. Жесткий NAT назначает разный публичный порт для каждого направления, поэтому адрес, который устройство получило от STUN-сервера, не совпадает с тем, который сможет использовать удаленный узел. Tailscale сообщает об этом в netcheck как MappingVariesByDestIP: true.
Один жесткий NAT преодолим. Если у другой стороны есть стабильный публичный endpoint, устройство за жестким NAT все равно может установить соединение, и путь будет сформирован. Два жестких NAT одновременно приводят к сбою, так как ни одна из сторон не может предсказать порт, на котором появится другая.
На VPS с публичным IPv4-адресом это поле должно содержать false, так как ничто не транслирует этот адрес. Если на арендованном сервере отображается true, значит, адрес транслируется где-то в сети провайдера, и никакие правила брандмауэра внутри машины это не изменят. Ваши варианты: разместить peer relay на машине, у которой есть чистый публичный endpoint, или перенести рабочую нагрузку. Это также тот случай, когда анонсирование ваших частных диапазонов через subnet router приносит пользу, поскольку вам потребуется один надежный путь в сеть, а не хороший путь к каждому устройству в ней.
Почему при использовании exit node Tailscale кажется медленнее, чем есть на самом деле
Exit node — это второй узел в цепочке, и пользователи часто ошибочно винят в задержках сам туннель. При включенной exit node запрос уходит с вашего ноутбука, проходит через туннель до VPS, выходит с VPS в публичный интернет, а ответ возвращается тем же путем. Даже при идеально прямом соединении до этого VPS общая скорость не может превышать пропускную способность канала самого VPS, а дополнительное расстояние сказывается на времени загрузки каждой страницы.
Измеряйте эти два участка по отдельности. Отключите exit node и протестируйте туннель напрямую, обращаясь к tailnet-адресу вашего VPS:
sudo tailscale set --exit-node=
sudo apt install -y iperf3
iperf3 -sЗапустите iperf3 -c 100.113.160.82 с клиента, указав этот tailnet-адрес. Полученное значение — это скорость вашего туннеля. Теперь включите exit node обратно с помощью sudo tailscale set --exit-node=100.113.160.82 и запустите обычный тест скорости до публичного интернета. Это число будет отражать скорость туннеля плюс пропускную способность канала VPS. Если первое значение в норме, а второе низкое, проблема не в Tailscale, и искать причину нужно в сети и параметрах самой exit node. Команда tailscale exit-node list покажет доступные узлы, если вы не уверены, какой именно узел выбрали.
Вторая причина ограничения скорости exit node — процессор. Рекомендация Tailscale заключается в том, чтобы отдавать предпочтение современным поколениям CPU с более высокой тактовой частотой, а не большему количеству ядер, поэтому тариф с большим числом vCPU не всегда будет быстрее. На загруженном общем хосте выделенные вам ресурсы CPU могут быть недоступны в полном объеме, и steal time от «шумных соседей» проявляется как изменение пропускной способности в течение дня, даже если с вашей стороны ничего не менялось.
Единственный параметр настройки: rx-udp-gro-forwarding
Tailscale описывает одну настройку Linux, которая применяется к машинам, пересылающим трафик, то есть к exit nodes и subnet routers. Обычный клиент не получит преимуществ. Требуется Tailscale версии 1.54 или новее и ядро Linux версии 6.2 или новее, поэтому убедитесь в соблюдении обоих условий перед внесением изменений:
tailscale version
uname -rПосле этого включите пересылку UDP GRO (generic receive offload) на интерфейсе, который смотрит в сторону интернета:
NETDEV=$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")
sudo ethtool -K $NETDEV rx-udp-gro-forwarding on rx-gro-list offПроверьте, что настройка применилась:
ethtool -k $NETDEV | grep -E 'rx-udp-gro-forwarding|rx-gro-list'Вы должны увидеть rx-udp-gro-forwarding: on и rx-gro-list: off. Это помогает, так как трафик Tailscale передается по UDP, и если позволить ядру сохранять небольшие UDP-пакеты объединенными на всем пути пересылки, демон будет обрабатывать меньше сегментов большего размера при том же объеме данных. Настройка ethtool -K не сохраняется после перезагрузки, поэтому ее нужно сделать постоянной. В системе, использующей networkd-dispatcher:
printf '#!/bin/sh\n\nethtool -K %s rx-udp-gro-forwarding on rx-gro-list off \n' "$(ip -o route get 8.8.8.8 | cut -f 5 -d " ")" | sudo tee /etc/networkd-dispatcher/routable.d/50-tailscale
sudo chmod 755 /etc/networkd-dispatcher/routable.d/50-tailscaleЗапустите скрипт вручную один раз и убедитесь, что код завершения равен 0. Узлу пересылки также требуется включенная IP-маршрутизация, что является отдельной настройкой и отдельной причиной сбоев:
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.confКакое значение MTU использует ваш интерфейс tailscale0?
Перестаньте угадывать это число и посмотрите его прямо на машине:
ip link show tailscale0Значение mtu в этом выводе — это то, что реально использует ваш туннель, и оно меньше 1500, которые сообщает ваш Ethernet-интерфейс. Это сделано намеренно, а не является ошибкой. Каждый пакет, который вы отправляете внутри туннеля, упаковывается: внешний IP-заголовок размером 20 байт для IPv4 или 40 для IPv6, UDP-заголовок размером 8 байт, а также фрейминг WireGuard и тег аутентификации размером 32 байта. Всё это должно поместиться в то, что может передать реальный канал связи. Tailscale выбирает значение, достаточно низкое для работы в сетях, которые пропускают пакеты меньше стандартных 1500 байт, включая PPPoE-соединения, некоторые мобильные сети и IPv6-туннели.
Симптом проблемы с MTU специфичен, поэтому не стоит диагностировать её только по медленной работе. SSH работает отзывчиво, ping выполняется успешно, а затем передача больших объемов данных или загрузка тяжелых HTTPS-страниц полностью зависает, а не просто замедляется. Такой паттерн означает, что пакеты избыточного размера где-то отбрасываются, а ICMP-сообщение, которое должно уведомить отправителя, не возвращается. Увеличение MTU tailscale0 до 1500 только ухудшит ситуацию, так как пакеты, которые и так не помещаются, станут ещё больше. Правильное решение — найти рабочее значение MTU методом деления пополам и ограничить TCP MSS на маршрутизаторе, который пересылает трафик. Тип соединения на это не влияет: ретранслируемый путь и прямой путь используют одно и то же значение MTU интерфейса.
FAQ
Как узнать, является ли соединение Tailscale прямым или ретранслируемым?
Запустите tailscale status и посмотрите на конец строки нужного узла. direct 203.0.113.9:41641 означает прямое соединение, relay "tor" — что все пакеты проходят через указанный DERP-сервер, а peer-relay — что пакеты передаются через другое устройство в вашей tailnet. Для дополнительной проверки запустите tailscale ping <peer>: при исправном прямом пути команда начинает работу с DERP, а затем выводит pong с обычным IP-адресом и портом. Ретранслируемый путь будет выводить DERP pongs до самого конца, пока выполнение не завершится с direct connection not established. Сначала отправьте немного трафика на узел, так как Tailscale строит маршрут только по запросу.
Почему мой VPS никогда не устанавливает прямое соединение?
Запустите tailscale netcheck на VPS. Если команда выводит UDP: false, значит, исходящий межсетевой экран блокирует исходящий UDP-трафик, и демон переключился на DERP через TCP 443, поэтому устройство отображается как подключенное. Разрешите исходящий UDP-трафик с порта 41641 на любые адреса, а также исходящий UDP-трафик на любые адреса через порт 3478. Проверьте как сетевой экран провайдера, так и локальный межсетевой экран на сервере: это разные уровни контроля, и правило ufw не влияет на настройки провайдера.
Менее безопасно ли ретранслируемое соединение Tailscale, чем прямое?
Нет. DERP-сервер пересылает пакеты WireGuard, которые он не может расшифровать, так как ключи шифрования генерируются на ваших устройствах и никогда их не покидают. Цена ретрансляции — это задержки и пропускная способность, а не конфиденциальность. Сервер координации управляет тем, какие устройства узнают друг о друге, и разделение между ключевым материалом и метаданными соединения стоит изучить, прежде чем решать, какую часть инфраструктуры вы хотите разместить самостоятельно.
Помогает ли настройка rx-udp-gro-forwarding всем машинам?
Нет. Она предназначена для Linux-машин, которые пересылают трафик для других узлов, то есть для exit nodes и subnet routers. Ноутбук или сервер, который общается только со своими собственными узлами, не получит от этого преимуществ. Также требуются Tailscale версии 1.54 или новее и ядро Linux версии 6.2 или новее, поэтому сначала проверьте tailscale version и uname -r. Помните, что ethtool -K сбрасывается после перезагрузки, если не настроить сохранение параметров.
Работает ли Tailscale медленнее, чем обычный WireGuard?
Оба решения используют WireGuard для шифрования трафика. Tailscale добавляет механизм настройки соединения, который в обычном WireGuard нужно выполнять вручную, и именно этот процесс иногда приводит к использованию ретранслятора. У обычного WireGuard нет ретрансляторов: он либо подключается напрямую, либо не подключается вовсе. Сравнивайте аналогичные сценарии и проводите замеры производительности Tailscale только тогда, когда tailscale status показывает direct. Если вы хотите сравнить с версией, настроенной вручную, самостоятельно развернутый сервер WireGuard потребует около сорока строк конфигурации, а компромиссы этого подхода описаны в сравнении двух методов.