Что такое Tailscale и как работает эта VPN-сеть
Узнайте, как Tailscale создает зашифрованные WireGuard туннели между узлами. Разбираем работу координационного сервера, механизмы NAT traversal и модель угроз сети.
Что такое Tailscale?
Tailscale — это VPN, который соединяет ваши устройства напрямую друг с другом, вместо того чтобы направлять весь трафик через один шлюз под вашим управлением. Каждый узел использует WireGuard, поэтому пакеты передаются между серверами в зашифрованном виде, и никто на пути следования не может их прочитать. Хостинговый координационный сервер выполняет функцию посредника. Он хранит и распространяет открытые ключи, а также сообщает каждому узлу, где находятся остальные. Кроме того, он передает правила доступа, которые вы создали.
Это разделение лежит в основе всей архитектуры. Плоскость данных работает по принципу peer-to-peer, а обмен между узлами зашифрован. Плоскость управления — это сервис, который Tailscale предоставляет вам. Любой важный вопрос о Tailscale, включая неудобные вопросы о доверии, вытекает из этих двух фактов. Если вы уже настраивали VPN на базе WireGuard вручную на VPS, то Tailscale — это тот же самый туннель, в котором распределение ключей и обход межсетевых экранов выполнены за вас.
Как работает Tailscale?
Ваша частная сеть узлов называется tailnet. Когда машина присоединяется к ней, происходят четыре вещи.
- Запускается демон
tailscaled, генерирует пару ключей WireGuard и сохраняет свое состояние в/var/lib/tailscale/tailscaled.state. Приватный ключ остается на этой машине. Формулировка Tailscale предельно ясна: «приватный ключ никогда, ни при каких обстоятельствах не покидает свой узел». - Узел авторизуется на координационном сервере и загружает свой публичный ключ, а также адреса, по которым, как он считает, с ним можно связаться. Tailscale описывает этот сервер как «общий почтовый ящик для публичных ключей».
- Координационный сервер отправляет в ответ карту сети: публичный ключ, адрес в tailnet, имя машины и возможные точки доступа каждого узла, к которому данному узлу разрешено подключаться.
- Затем каждая пара узлов пытается построить прямой туннель WireGuard между собой. Если это не удается, они передают пакеты через ретранслятор.
Каждый узел получает стабильный адрес из диапазона 100.64.0.0/10 — это диапазон carrier-grade NAT от 100.64.0.0 до 100.127.255.255. Tailscale использует этот диапазон, так как он зарезервирован для инфраструктуры провайдеров и редко конфликтует с частными адресами, которые уже используются на ваших серверах. В Linux туннель отображается как интерфейс с именем tailscale0.
Реализация WireGuard работает внутри tailscaled в пространстве пользователя, а не в модуле ядра. Именно поэтому Tailscale запускается в контейнерной виртуализации, где sudo modprobe wireguard завершается с ошибкой Operation not supported. Это также означает, что предел пропускной способности на конкретном узле ниже, чем у WireGuard в ядре, что является одним из компромиссов, описанных в Tailscale в сравнении с обычным WireGuard.
Две команды позволяют оценить текущее состояние.
tailscale ip -4
tailscale statustailscale status выводит по одной строке на каждый узел, и последний столбец является наиболее важным.
100.101.102.103 web-1 you@ linux -
100.101.102.104 db-1 you@ linux active; direct 198.51.100.24:41641
100.101.102.105 ci-runner you@ linux active; relay "fra"direct с указанием адреса и порта означает, что две машины нашли путь друг к другу и трафик передается напрямую (peer-to-peer). relay "fra" означает, что трафик проходит через ретранслятор Tailscale во Франкфурте. - означает, что в данный момент активная сессия с этим узлом отсутствует, что является нормальным поведением.
Что сервер координации может и чего не может видеть
Сервер координации хранит открытые ключи и метаданные. Он знает имена ваших машин, какой пользователь или тег владеет каждым узлом, tailnet-адрес каждого узла, публичные адреса, по которым доступны ваши узлы, время последнего выхода каждого узла в сеть, а также созданный вами файл политик. Это полная карта вашего парка устройств.
Он не хранит закрытые ключи, поэтому не может расшифровать трафик между двумя узлами. Шифрование осуществляется по принципу end-to-end между узлами WireGuard, а сервер координации не является участником этого обмена.
Что он может делать, так это передавать ключи. Любому серверу координации, будь то облачный или развернутый самостоятельно, доверяется задача сообщать вашим узлам, какие открытые ключи принадлежат данной tailnet. Это ключевой момент модели угроз, описанной ниже, и причина, по которой существует Headscale, сервер координации с открытым исходным кодом для самостоятельного хостинга.
Как два сервера за разными файрволами общаются напрямую
NAT (network address translation) позволяет множеству машин использовать один публичный адрес. Ваш VPS обычно имеет собственный публичный адрес, но другие машины, которые вы хотите включить в tailnet, часто его не имеют: домашний сервер, сборочный узел в офисной сети или устройство за файрволом провайдера, который вы не можете настроить.
Tailscale находит путь, используя методы, основанные на стандартах STUN (session traversal utilities for NAT) и ICE. Каждый узел отправляет небольшой UDP-пакет на STUN-сервер и узнает публичный адрес и порт, которые его маршрутизатор назначил этому сокету. Оба узла сообщают эти кандидаты координационному серверу, который передает их другой стороне. Затем оба узла начинают одновременно отправлять пакеты друг другу. Каждый маршрутизатор сначала видит исходящий пакет, поэтому он создает правило трансляции и принимает ответ, приходящий с того же адреса. Ни одной из сторон не потребовалось создавать входящее правило в файрволе.
Используются специфические порты. Прямые туннели WireGuard используют UDP с портом источника, который по умолчанию равен 41641. STUN работает через UDP 3478 с релейными серверами Tailscale. Управляющее соединение и любые ретранслируемые данные используют HTTPS через TCP 443. В большинстве случаев вам не нужно открывать входящие порты, хотя в сети со сложным NAT разрешение входящего трафика по UDP 41641 повышает вероятность прямого соединения.
tailscale netcheckПрочитайте две строки этого отчета. UDP: true означает, что UDP вообще покидает машину, а UDP: false означает, что каждое соединение с этого узла будет ретранслироваться. MappingVariesByDestIP: true означает, что маршрутизатор назначает разный публичный порт для каждого пункта назначения, поэтому предсказание адреса, описанное выше, не работает, и такие узлы обычно остаются в режиме ретрансляции.
Когда Tailscale использует ретранслятор DERP
DERP (designated encrypted relay for packets) — это резервный механизм. Tailscale поддерживает ретрансляторы во многих регионах, доступные по протоколу TCP 443. Если у узла нет прямого пути, он отправляет свои пакеты WireGuard через один из них.
Пакеты остаются зашифрованными. Tailscale заявляет об этом прямо: «у сервера DERP нет никакой возможности расшифровать ваш трафик. Он просто слепо пересылает уже зашифрованные пакеты от одного узла к другому». Ретранслятор видит только зашифрованные данные и знает, какой узел общается с каким.
Ретрансляторы также передают первые пакеты большинства соединений. Поиск прямого пути занимает некоторое время, поэтому сессия часто начинается через ретранслятор и переключается на прямое соединение, как только узлы обнаруживают друг друга. Вы можете наблюдать за этим процессом.
tailscale ping db-1Первые ответы приходят как via DERP(fra), а в последующей строке отображается что-то вроде via 198.51.100.24:41641. Это изменение означает переход на прямой туннель. Если состояние не меняется, выполните tailscale netcheck на обоих концах. Ретранслируемый путь продолжает работать. Это увеличивает задержку, так как каждый пакет делает крюк через третью машину. Если вы заметили медленную передачу данных, а не разрыв соединения, почему ретранслируемое соединение Tailscale работает значительно медленнее прямого поможет оценить разницу и покажет, как настроить VPS для работы по прямому пути.
Подключение VPS к вашей tailnet
Скрипт установки поддерживает Ubuntu и Debian.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale upsudo tailscale up выводит URL. Откройте его, пройдите аутентификацию, и узел появится в вашей панели администратора. Затем убедитесь, что демон запускается после перезагрузки, так как этот шаг часто пропускают.
sudo systemctl is-enabled tailscaled
tailscale statusis-enabled должен вывести enabled, а tailscale status должен показать новый узел с его адресом 100.x. Для сервера, развернутого с помощью скрипта, интерактивный URL не подходит. Создайте ключ аутентификации в панели администратора и передайте его вместе с тегом, который определяет тип этой машины.
sudo tailscale up --auth-key=tskey-auth-REPLACE-ME --advertise-tags=tag:serverТегированный узел принадлежит тегу, а не пользователю, который выполнил команду, поэтому он продолжает работать после удаления учетной записи этого пользователя. Тег должен быть предварительно объявлен в вашем файле политик в разделе tagOwners, иначе команда будет отклонена. Тегирование также влияет на то, как машина учитывается в вашем тарифном плане, поскольку тегированный ресурс тарифицируется отдельно от личных устройств пользователя, а в том, что на самом деле покрывает бесплатный тариф указаны соответствующие лимиты.
Для парка серверов важны две настройки. Ключи узлов по умолчанию истекают через 180 дней (по состоянию на август 2026 года), и после истечения срока действия ключа «соединения с данным узлом и от него перестанут работать» до тех пор, пока кто-либо не выполнит вход снова. Поэтому откройте строку с машиной в панели администратора и выберите Disable Key Expiry для серверов, работающих без присмотра. MagicDNS, включенный по умолчанию для tailnet, созданных 20 октября 2022 года или позже, присваивает каждому узлу имя, например db-1.yak-bebop.ts.net, которое разрешается через stub resolver по адресу 100.100.100.100. Используйте имена вместо адресов, так как пересобранный узел получает новый адрес, но сохраняет свое имя.
Если установка завершается ошибкой при работе с apt или репозиторием, распространенные ошибки установки Tailscale в Ubuntu содержат способы их устранения.
Доступ к сервису, привязанному к localhost
Здесь пригождается tailnet, и именно здесь часто возникают трудности. Подключение к tailnet не делает сервис, работающий через loopback, доступным извне.
ss -tlnp | grep 3000Если эта команда выводит 127.0.0.1:3000, значит сокет принимает только пакеты, адресованные на 127.0.0.1. Запрос от другого узла приходит на адрес 100.x этого узла, поэтому ядро не находит слушающего процесса и отвечает TCP-сбросом. Клиент сообщает об ошибке Connection refused. Туннель исправен. Проблема заключается в настройках слушающего процесса.
Существует два корректных решения. Привяжите сервис к адресу tailnet вашего узла: это исключит его из публичного интерфейса без использования прокси. Передайте --bind 100.101.102.104 или эквивалентную опцию в конфигурации, а для контейнера опубликуйте порт как -p 100.101.102.104:3000:3000. Либо оставьте сервис на loopback и установите перед ним Tailscale.
tailscale serve 3000Это проксирует запросы на http://127.0.0.1:3000 и обслуживает их внутри вашего tailnet по имени ts.net через HTTPS, если для tailnet включены HTTPS-сертификаты. Сервис останется доступным только для ваших узлов. Публичная версия этого решения называется Funnel, а в Tailscale serve и funnel описано, какой вариант выбрать.
Две связанные задачи вынесены на отдельные страницы. Для доступа к целой частной сети, где не установлен Tailscale, требуется subnet router на VPS, а для перенаправления исходящего интернет-трафика узла через другой узел требуется exit node.
Закрытие портов, которые больше не нужны
Как только администратор получает доступ к серверу через tailnet, публичный порт 22 становится не нужен. В этом заключается практическая польза: закрытый порт невозможно подвергнуть брутфорсу, а логи перестают заполняться попытками взлома.
Порядок действий имеет значение. Сначала настройте доступ через tailnet, убедитесь, что можете войти через него в рамках второй сессии, и только после этого удаляйте публичное правило.
sudo ufw allow in on tailscale0
sudo ufw status verboseПосле этого удалите публичное правило SSH и переподключитесь, используя имя MagicDNS. Учтите, что именно делает ufw allow in on tailscale0: этот инструмент доверяет всему трафику, поступающему через туннель, поэтому файл политик Tailscale становится основным средством контроля доступа вместо ufw. Составляйте политики с учетом этого факта.
Предупреждение для тех, кто использует контейнеры. Опубликованный порт Docker создает собственные правила NAT и обходит ufw, поэтому ufw deny не закрывает его. В опубликованных портах Docker, обходящих ufw объясняется этот механизм. Публикация на адрес tailnet, как описано выше, позволяет избежать этой проблемы. Если приложение работает через Docker Compose, sidecar-контейнер Tailscale в стеке Compose идет еще дальше и полностью убирает опубликованный порт, оставляя контейнер доступным только по его имени в tailnet.
Что защищает Tailscale, а что нет
Это стоит прояснить, так как маркетинговые материалы часто размывают границы.
Защищено: трафик между двумя узлами шифруется сквозным образом с помощью WireGuard, и ни один промежуточный ретранслятор не может его прочитать. Приватные ключи никогда не покидают машину, на которой были созданы. Узлам не требуются открытые входящие порты, поэтому в Интернете нечего сканировать на наличие портов 22 или 5432. Доступ между узлами определяется файлом политик, а не тем, кто знает IP-адрес.
Не защищено: сервер координации видит граф ваших устройств. Эти метаданные сами по себе чувствительны, так как имена машин, владельцы, адреса и время нахождения в сети описывают вашу инфраструктуру. Сервер также распределяет ключи, что является более серьезным риском. Tailscale заявляет об этом прямо: «Если бы Tailscale действовал злонамеренно и скрытно добавил новые узлы в вашу сеть, он мог бы отправлять или принимать трафик от ваших существующих узлов в открытом виде». Ваш провайдер единого входа (SSO) находится на том же пути доверия, так как любой, кто может создать там учетную запись, может добавить узел. А скомпрометированный узел становится полноценным участником tailnet, поэтому он получает доступ ко всему, что разрешено вашими политиками. Является ли это приемлемым риском, зависит от того, против кого вы защищаетесь, а полная модель доверия подробно описывает каждый из этих случаев, включая то, что на самом деле может сделать злоумышленник с украденной учетной записью.
Существует два ответа на риск при распределении ключей. Первый — это tailnet lock, который требует, чтобы существующие доверенные узлы криптографически подписали новый узел, прежде чем остальные узлы примут его. Control plane, добавляющий узел без действительной подписи, игнорируется. Консоль администратора генерирует точную строку tailscale lock init для ваших подписывающих узлов, и каждый узел может подтвердить то, что он видит.
tailscale lock statusВсе узлы должны сообщать об одном и том же наборе доверенных ключей подписи. Второй ответ — запустить control plane самостоятельно. Самохостируемый сервер координации Headscale использует тот же протокол для тех же клиентов, что переносит граф устройств и распределение ключей на оборудование, которым владеете вы. Вы также берете на себя ответственность за время безотказной работы этого сервера. Если вы все еще сравниваете варианты самохостируемых control plane, а не остановились на этом, NetBird — это отдельный mesh VPN, сервер которого вы запускаете целиком на одном VPS.
Один параметр по умолчанию, который нужно исправить в первый же день. Новая tailnet поставляется с разрешительными настройками: «политика tailnet по умолчанию разрешает обмен данными между всеми устройствами внутри tailnet». Как только вы добавляете секцию acls, модель меняется на «запрещено по умолчанию», и пропускаются только ваши правила.
{
"tagOwners": {
"tag:server": ["autogroup:admin"]
},
"acls": [
{"action": "accept", "src": ["autogroup:member"], "dst": ["tag:server:22"]}
]
}Эта политика позволяет участникам tailnet подключаться по SSH к помеченным серверам и больше ни к чему. Добавляйте правила для каждого сервиса отдельно, вместо того чтобы оставлять подстановочный знак (wildcard), так как подстановочный знак означает, что с помощью одного украденного ключа от ноутбука можно получить доступ к вашей базе данных.
Типичные сбои и сообщения об ошибках
tailscale status всегда выдает relay. Между двумя узлами не удалось установить прямой путь. Запустите tailscale netcheck на обоих концах. UDP: false означает, что исходящий UDP-трафик заблокирован, поэтому соединение возможно только через ретранслятор. MappingVariesByDestIP: true указывает на наличие жесткого NAT; проблему часто решает открытие входящего UDP-порта 41641 на стороне, которой вы управляете.
Узел, работавший месяцами, исчез. Истек срок действия ключа узла, который по умолчанию составляет 180 дней. В консоли администратора машина отображается как просроченная; команда sudo tailscale up на самом устройстве восстанавливает доступ. Отключите истечение срока действия ключей на серверах, чтобы это не повторилось.
Пиры видны в списке, но соединения прерываются по таймауту. Сетевое взаимодействие работает, но политика безопасности блокирует трафик. Проверьте раздел acls на наличие правила, охватывающего данный источник, назначение и порт. Отклоненный пакет отбрасывается без ответа, поэтому вместо сообщения Connection refused вы получаете таймаут.
Имена MagicDNS не разрешаются. ping db-1 завершается ошибкой, в то время как ping 100.101.102.104 работает. Какой-то процесс перезаписал /etc/resolv.conf, поэтому запросы не доходят до локального резолвера по адресу 100.100.100.100. Проверьте cat /etc/resolv.conf на наличие 100.100.100.100 и выясните, какие еще службы на сервере изменяют этот файл. Это проблема того же класса, что и нарушение работы DNS внутри туннеля WireGuard.
tailscale up отклоняет ваш тег. Тег не объявлен в разделе tagOwners файла политики. Добавьте его туда и повторно выполните команду.
FAQ
Является ли Tailscale VPN или mesh-сетью?
Оба термина верны, так как они описывают разные уровни системы. Туннели строятся на базе WireGuard, что делает систему VPN. Топология является mesh-сетью, поскольку каждый узел устанавливает прямое соединение с другим узлом, с которым он взаимодействует, вместо того чтобы пропускать все пакеты через центральный сервер. Сервер координации находится в плоскости управления, а не в плоскости передачи данных, поэтому при потере связи с ним существующие туннели продолжают передавать трафик. Во время сбоя невозможно лишь подключение новых узлов и обновление ключей или политик.
Может ли Tailscale читать мой трафик?
Содержимое — нет. Трафик шифруется сквозным образом между узлами с помощью WireGuard, закрытые ключи никогда не покидают узлы, а ретрансляторы DERP пересылают пакеты, которые они не могут расшифровать. Tailscale видит метаданные: имена машин, владельцев, открытые ключи, адреса конечных точек и время нахождения узла в сети. Также компания занимается распределением ключей, поэтому скомпрометированный сервер координации теоретически может попытаться добавить узел, которому ваша сеть начнет доверять. Функция Tailnet lock предотвращает это, требуя подписи от ваших собственных доверенных узлов, а использование Headscale полностью исключает сторонний сервер управления из схемы.
Нужно ли открывать порты на фаерволе для Tailscale?
Входящие — почти никогда. Согласно рекомендациям Tailscale, «в большинстве случаев открывать порты на фаерволе не требуется». Для исходящих соединений узлу нужен TCP 443 для связи с сервером координации и ретрансляторами, а также UDP 3478 для STUN. Прямые туннели используют UDP с портом, который по умолчанию равен 41641. Разрешение входящего трафика на UDP 41641 является опциональным и помогает успешному установлению прямых соединений в сложных сетевых конфигурациях.
Почему другие узлы не могут подключиться к моему сервису на порту 3000?
Сначала проверьте адрес привязки (bind address) с помощью ss -tlnp. Слушатель на 127.0.0.1:3000 отклоняет соединения, которые приходят на 100.x адрес узла в tailnet, так как этот сокет принимает только запросы, направленные на loopback, и клиент получает Connection refused. Привяжите сервис к адресу в tailnet или используйте tailscale serve 3000 для проксирования. Если слушатель уже настроен на 0.0.0.0, а соединение прерывается по таймауту вместо отказа, причина кроется в правилах политики или локальном фаерволе, а не в адресе привязки.
Стоит ли использовать Headscale вместо сервера координации Tailscale?
Используйте Headscale, если граф устройств или распределение ключей должны находиться на инфраструктуре под вашим контролем, или если работа tailnet не должна зависеть от внешнего сервиса. Клиенты и протокол остаются теми же. Обратная сторона — вы берете на себя обслуживание сервера координации, и его сбой приведет к невозможности подключения новых узлов и применения изменений в политиках. Для небольшого парка устройств использование облачного сервера управления с включенным tailnet lock обычно является более рациональным выбором.