SSD Nodes Learn 🎉 VPS от $4.99/мес
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-08

Настройка Tailscale subnet router на VPS

Пошаговое руководство по настройке subnet router в Tailscale на VPS. Узнайте, как включить IP forwarding, настроить флаг --accept-routes и сохранить маршруты после перезагрузки.

Что делает subnet router в Tailscale

Subnet router в Tailscale — это устройство, которое анонсирует диапазон частных IP-адресов в вашу tailnet, позволяя всем устройствам в сети обращаться к этим адресам, даже если на них не установлен Tailscale. Ваша tailnet — это частная сеть Tailscale, состоящая из устройств, авторизованных в одной учетной записи или организации. Exit node — это функция, которую часто путают с subnet router, хотя она выполняет противоположную задачу. Она направляет весь трафик устройства через VPS, делая этот VPS точкой выхода устройства в публичный интернет.

Каждое предложение описывает одну функцию. Subnet router делает частную сеть доступной из tailnet. Exit node меняет точку выхода вашего публичного трафика. Если вам нужна именно вторая функция, ознакомьтесь с руководством как запустить Tailscale exit node на VPS. Это разные флаги, и один VPS может выполнять обе задачи одновременно, но они решают разные проблемы и имеют разные причины сбоев.

Когда VPS требуется в качестве subnet router

Типичный сценарий — частная сеть, предоставленная провайдером. Ваш VPS имеет публичный адрес и второй интерфейс в частном сегменте, а остальные серверы в этом сегменте не имеют публичных адресов: база данных на 10.0.0.20, целевой сервер резервного копирования на 10.0.0.30. Установите Tailscale на один VPS, анонсируйте 10.0.0.0/24, и ваш ноутбук получит прямой доступ к этим частным адресам. Конфигурация сегмента при этом не меняется, а база данных по-прежнему остается без публичного адреса.

Другой случай — сеть, расположенная за VPS. Это может быть домашняя или офисная LAN (локальная сеть) за собственным маршрутизатором, либо стойка оборудования, на котором невозможно запустить Tailscale, например, управляемый коммутатор или старое сетевое хранилище (NAS) с закрытой прошивкой. Один Linux-хост в этой сети становится subnet router для всех остальных устройств.

Оба случая объединяет одно требование. Subnet router должен иметь доступ к диапазону, который он анонсирует, используя собственную таблицу маршрутизации и настройки межсетевого экрана. Tailscale не создает это соединение. Программа доставляет трафик до маршрутизатора и передает его ядру для дальнейшей пересылки.

Установка Tailscale и проверка локального маршрута

curl -fsSL https://tailscale.com/install.sh | sh

Скрипт определяет дистрибутив, добавляет репозиторий пакетов Tailscale, устанавливает команду tailscale и демон tailscaled, а затем активирует службу. Подтвердите это с помощью systemctl is-active tailscaled, команда должна вывести active.

Прежде всего, убедитесь, что VPS имеет доступ к сети, которую вы планируете анонсировать.

ip route show
ping -c3 10.0.0.20

ip route show должен отобразить частный диапазон на реальном интерфейсе, например, 10.0.0.0/24 dev enp7s0 proto kernel scope link src 10.0.0.5. Если ping не проходит здесь, на самом маршрутизаторе, никакой флаг Tailscale не поможет. Проблема заключается в сетевой конфигурации VPS или межсетевом экране на целевом хосте. Исправьте это в первую очередь, так как от этого зависят все последующие тесты.

Включение IP forwarding с сохранением настройки после перезагрузки

Машина под управлением Linux отбрасывает любой пакет, не адресованный ей самой, если функция пересылки (forwarding) отключена. Пересылка пакетов других машин — основная задача subnet router, поэтому этот шаг обязателен.

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

Проверьте состояние с помощью sysctl net.ipv4.ip_forward, команда должна вывести net.ipv4.ip_forward = 1.

Часто этот шаг выполняют лишь частично. Команда sudo sysctl -w net.ipv4.ip_forward=1 срабатывает немедленно, но сбрасывается после перезагрузки. В результате subnet router работает неделями, а затем перестает функционировать после обновления ядра и перезагрузки системы. Проблема в том, что внешне всё выглядит исправно. В tailscale status узел по-прежнему отображается как активный, в панели администратора маршрут одобрен, а на клиентах он установлен. Пакеты доходят до VPS, но ядро отбрасывает их без записи в лог. Запись значений в /etc/sysctl.d/99-tailscale.conf обеспечивает сохранение настроек после перезагрузки.

Если вы анонсируете маршруты при выключенном forwarding, tailscale up выдаст предупреждение, похожее на Warning: IPv4 forwarding is disabled. Subnet routes and exit nodes may not work correctly.. Читайте вывод этой команды, а не пропускайте его.

Анонсирование маршрутов

sudo tailscale up --advertise-routes=10.0.0.0/24

На VPS, который уже подключен к вашей tailnet, измените настройки на месте:

sudo tailscale set --advertise-routes=10.0.0.0/24

Используйте tailscale set для любых последующих изменений. Повторный запуск tailscale up с одним флагом сбрасывает все флаги, которые вы не указали, поэтому CLI выдаст ошибку о том, что изменение настроек таким способом требует перечисления всех нетиповых флагов. tailscale set изменяет одну настройку, не затрагивая остальные.

Несколько диапазонов указываются в одном списке через запятую без пробелов: --advertise-routes=10.0.0.0/24,192.168.50.0/24. Каждая запись должна быть сетевым адресом в нотации CIDR (бесклассовая междоменная маршрутизация, формат 10.0.0.0/24). Ошибочный ввод собственного адреса хоста, 10.0.0.5/24, будет отклонен, так как биты после префикса не равны нулю; в сообщении об ошибке будет указан префикс, который вы, вероятно, имели в виду. Чтобы прекратить анонсирование, установите пустой список с помощью sudo tailscale set --advertise-routes=.

Одобрение маршрута в консоли администратора

Анонсирование маршрута — это лишь запрос, а не изменение конфигурации. Пока администратор не одобрит его, ни один клиент не получит этот маршрут, и доступ к диапазону адресов будет закрыт. Это сделано намеренно: машина, способная самостоятельно добавить себя в таблицу маршрутизации всех узлов, может перехватывать трафик для любого диапазона.

Одобрите маршрут на странице Machines в консоли администратора. VPS будет помечен значком подсети. Разверните строку с узлом, найдите раздел subnets, перейдите к настройкам маршрутов, отметьте нужный маршрут и сохраните изменения.

Одобрение выполняется для каждого префикса отдельно. Если вы анонсируете 10.0.0.0/24 сегодня, а 192.168.50.0/24 в следующем месяце, новый префикс поступит в статусе «не одобрено», в то время как старый продолжит работать. Со стороны VPS одобренный и игнорируемый маршруты выглядят одинаково, поэтому перед началом отладки проверьте состояние в консоли.

Вы можете пропустить ручной этап, используя блок autoApprovers в файле политики tailnet:

{
  "autoApprovers": {
    "routes": {
      "10.0.0.0/24": ["tag:subnet-router"]
    }
  }
}

Затем запустите узел с этим тегом, sudo tailscale up --advertise-routes=10.0.0.0/24 --advertise-tags=tag:subnet-router, и маршрут будет одобрен сразу после анонсирования. Тег должен быть предварительно добавлен в раздел tagOwners того же файла политики. Это стоит настроить, если вы пересоздаете VPS с помощью скриптов, так как пересозданный узел считается новым, и его маршруты снова потребуют одобрения.

Почему Linux-клиенты игнорируют маршрут без --accept-routes

Маршрут анонсирован и одобрен. Ваш телефон и Mac могут связаться с 10.0.0.20. Ваш ноутбук на Linux — нет, при этом в консоли администратора нет никаких признаков проблемы.

Принятие маршрута подсети означает внесение записей в таблицу маршрутизации клиента. В Android, iOS, macOS, tvOS и Windows клиент Tailscale делает это автоматически. В Linux этого не происходит, так как машина на Linux часто является сервером или маршрутизатором, чья таблица маршрутизации была настроена намеренно. Автоматическое добавление /24, полученного из сети, может нарушить трафик, который эта машина уже обрабатывает. Поэтому в Linux вы должны дать явное согласие на каждом клиенте:

sudo tailscale set --accept-routes

Затем проверьте, куда был добавлен маршрут:

ip route show table 52
ip route get 10.0.0.20

Tailscale в Linux не помещает принятые маршруты в основную таблицу маршрутизации. Он помещает их в таблицу маршрутизации 52 и устанавливает правила политики, видимые через ip rule show в диапазоне приоритетов от 5210 до 5270, которые направляют несовпадающие пакеты в эту таблицу. Поэтому ip route show сам по себе никогда не покажет 10.0.0.0/24, и пользователь, который проверяет только эту команду, решит, что --accept-routes ничего не сделал. ip route show table 52 — это команда, которая показывает реальное положение дел, и она должна отображать анонсированный диапазон в tailscale0.

Стоит знать об одном исключении. Если этот узел Linux сам является вторым маршрутизатором подсети для своей локальной сети, --accept-routes заставит его отправлять трафик для своей собственной напрямую подключенной подсети через другой маршрутизатор, а не через свой интерфейс. На резервном маршрутизаторе в паре высокой доступности оставьте --accept-routes выключенным и используйте только анонсирование.

Режим сбоя: два маршрутизатора анонсируют пересекающиеся диапазоны

Два subnet-маршрутизатора не должны анонсировать идентичные диапазоны. Пересекающиеся диапазоны с разной длиной префикса допустимы, и Tailscale выбирает наиболее специфичный маршрут. Если маршрутизатор A анонсирует 10.0.0.0/24, а маршрутизатор B анонсирует 10.0.0.0/16, трафик для 10.0.0.20 будет направлен на A.

Неожиданным для пользователей является поведение системы при отключении узла A. Tailscale не переключается на менее специфичный маршрут. Трафик для 10.0.0.20 перестает проходить, в то время как трафик для 10.1.0.20 продолжает работать через B. Симптомы выглядят как частичная недоступность частной сети, а причина заключается в том, что отключенный узел удерживает более специфичный префикс. Если вам требуется отказоустойчивость, настройте маршрутизатор с более широким диапазоном так, чтобы он также анонсировал более узкие префиксы; тогда оба узла будут покрывать одни и те же адреса.

Другой тип пересечения возникает ближе к клиенту. Если вы находитесь в сети отеля с адресацией 192.168.1.0/24, а ваш subnet-маршрутизатор анонсирует 192.168.1.0/24, они начинают конкурировать за одни и те же пункты назначения, и результат зависит от платформы. В Linux установите правило с приоритетом выше, чем у Tailscale, чтобы локальные адреса использовали основную таблицу:

sudo ip rule add to 192.168.1.0/24 priority 2500 lookup main

Это правило не является постоянным и исчезнет после следующей перезагрузки. Настоящее решение заключается в выборе частного диапазона, который вы не встретите в публичных сетях. 192.168.0.0/24 и 192.168.1.0/24 являются значениями по умолчанию для большинства домашних маршрутизаторов, поэтому выберите что-то из диапазона 10.0.0.0/8, определив его заранее. Такое же столкновение нарушает работу обычного WireGuard VPN, настроенного вручную, по той же причине: более специфичный локальный маршрут выигрывает, поэтому трафик никогда не попадает в туннель.

Режим сбоя: DNS разрешается в адрес, который не покрыт маршрутом

Эту проблему сложно диагностировать, так как об ошибках ничего не сообщается. Имя разрешается. Соединение прерывается по тайм-ауту.

Допустим, db.internal.example.com разрешается в 10.0.5.20 через ваш частный DNS-сервер, а вы анонсировали 10.0.0.0/24. Поиск проходит успешно, так как разрешение DNS (domain name system) и IP-маршрутизация — это разные этапы, и ни один из них не проверяет другой. Затем пакет для 10.0.5.20 не находит подходящего маршрута в tailnet, поэтому он уходит через шлюз по умолчанию клиента и исчезает.

Две команды разделяют эти две части:

nslookup db.internal.example.com
ip route get 10.0.5.20

Если поиск возвращает адрес, но ip route get не отвечает через dev tailscale0, значит, с именем всё в порядке, а маршрут отсутствует. Анонсируйте диапазон, который покрывает этот адрес, либо 10.0.0.0/16, либо второй явный префикс, а затем одобрите новый префикс в консоли.

На самом DNS-сервере есть аналогичная ловушка. Если вы установите глобальный DNS-сервер в консоли администратора на частный адрес, например 10.0.0.53, этот адрес должен находиться внутри одобренного маршрута, иначе ваши устройства вообще не смогут связаться с резолвером. Включите опцию, которая переопределяет локальные DNS-серверы, указывая на резолвер, до которого никто не может достучаться, и каждое устройство в tailnet мгновенно потеряет разрешение имен, включая те, которые работали секунду назад. Сначала анонсируйте и одобрите маршрут до резолвера, а затем измените настройки DNS. Если DNS внутри туннеля — это то, с чем вы постоянно боретесь, в том, как DNS ломается в туннеле WireGuard описан тот же механизм без использования дополнительного уровня координации.

Source NAT и соединения типа site-to-site

По умолчанию subnet router перезаписывает исходный адрес каждого пересылаемого пакета на свой собственный частный адрес. Это называется SNAT (source network address translation), и этот механизм нужен для того, чтобы ответы доходили до отправителя без внесения изменений в настройки частной сети: база данных на 10.0.0.20 отвечает VPS, доступ к которому ей уже известен. Минус в том, что база данных видит каждое соединение tailnet как исходящее от VPS, поэтому правила межсетевого экрана и журналы доступа, основанные на исходном IP, не дают полезной информации.

Отключите эту функцию в Linux, если хотите сохранить реальный адрес tailnet клиента:

sudo tailscale set --snat-subnet-routes=false

Хостам в частной сети после этого потребуется маршрут обратно к 100.64.0.0/10 — диапазону, который Tailscale назначает устройствам, — указывающий на subnet router. Без этого обратного маршрута ответы будут уходить на шлюз по умолчанию и никогда не достигнут цели, из-за чего соединения будут зависать после первого пакета. Добавьте статический маршрут на шлюзе частной сети или оставьте SNAT включенным.

Соединение типа site-to-site — это два subnet router, выполняющих эту операцию одновременно: каждый анонсирует свою сеть и принимает сеть другого:

sudo tailscale up --advertise-routes=10.0.0.0/24 --snat-subnet-routes=false --accept-routes

Выполните соответствующую команду на другом маршрутизаторе, указав его собственный диапазон. Эти два диапазона должны отличаться. Если передача больших объемов данных зависает, в то время как ssh и ping работают нормально, причина кроется в MSS (maximum segment size) — максимальном размере блока данных, который может нести TCP-пакет. Служебные заголовки туннеля делают пересылаемые пакеты слишком большими для некоторых промежуточных звеньев сети, и ограничение (clamping) решает эту проблему:

sudo iptables -t mangle -A FORWARD -o tailscale0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

Сохраните это правило с помощью iptables-persistent, иначе оно исчезнет после следующей перезагрузки.

Обслуживание для обеспечения стабильной работы

По умолчанию ключи узлов (node keys) истекают через 180 дней, начиная с августа 2026 года. Когда ключ на subnet router становится недействительным, узел выходит из сети, и весь анонсированный диапазон становится недоступным, при этом в конфигурации не происходит никаких изменений, объясняющих это. Отключите истечение срока действия ключа для этой машины на странице Machines в панели администратора и зафиксируйте это действие в документации.

Tailscale отдает предпочтение прямому соединению между узлами, переключаясь на ретрансляционные серверы (relay servers) только при невозможности установить прямое подключение. Ретрансляторы работают стабильно, но увеличивают задержку. VPS с публичным IP-адресом — это простой случай: разрешите входящий трафик по UDP 41641, и большинство узлов подключатся напрямую. Если управление брандмауэром осуществляется через ufw, в разделе необходимые правила ufw для VPS описан нужный синтаксис.

Правила доступа (access rules) — это вторая важная составляющая. В стандартной tailnet каждое ваше устройство может связаться с любым другим, поэтому разрешенный маршрут работает сразу. Как только вы создаете политику ACL, сторона назначения в правиле должна содержать частный диапазон, так как 10.0.0.20 не является адресом tailnet и на него не распространяются правила, написанные для IP-адресов или тегов tailnet.

Наконец, решите, хотите ли вы использовать сервер координации, который вы не обслуживаете самостоятельно. Control plane в Tailscale — это облачный сервис. Ваши ключи остаются на ваших машинах, но учетная запись и файл политики хранятся там. Использование Headscale, self-hosted сервера управления Tailscale позволяет оставить всё на вашем собственном VPS, но требует затрат на поддержку. Если вы все еще выбираете между этой моделью и конфигурацией, написанной вручную, сравнение WireGuard и Tailscale объясняет, что дает уровень координации и какова его цена.

FAQ

В чем разница между subnet router и exit node?

Subnet router анонсирует диапазон частных адресов, чтобы устройства в tailnet могли обращаться к машинам, на которых не запущен Tailscale. Exit node анонсирует себя как маршрут во весь интернет, поэтому устройство направляет весь свой трафик через публичный адрес этого узла. Один VPS может выполнять обе функции. Это отдельные флаги, --advertise-routes и --advertise-exit-node, и каждый из них требует отдельного подтверждения в панели администратора.

Почему мой Linux-клиент игнорирует анонсированный маршрут подсети?

Linux-клиенты не принимают маршруты подсетей, пока вы их об этом не попросите. Выполните sudo tailscale set --accept-routes на клиенте. Затем проверьте результат с помощью ip route show table 52, а не ip route show. Tailscale устанавливает принятые маршруты в таблицу маршрутизации 52 и обращается к ним через правила политики, поэтому в основной таблице они не отображаются, и рабочий маршрут выглядит отсутствующим.

Моя подсеть перестала работать после перезагрузки. Что сломалось?

Скорее всего, IP forwarding. Значение, установленное через sysctl -w, не сохраняется после перезагрузки, поэтому запишите его в /etc/sysctl.d/99-tailscale.conf и подтвердите с помощью sysctl net.ipv4.ip_forward. Если пересылка включена, а диапазон всё ещё недоступен, проверьте узел в панели администратора. Ключи узлов по умолчанию истекают через 180 дней, и истекший срок действия subnet router выглядит как сетевая ошибка, а не как проблема с учетной записью.

Могут ли два subnet router анонсировать один и тот же диапазон?

Идентичные диапазоны — нет. Пересекающиеся диапазоны с разной длиной префикса допустимы, и приоритет получает наиболее специфичный из них. При настройке отказоустойчивости нужно быть осторожным: когда маршрутизатор с более специфичным префиксом отключается, Tailscale не переключается автоматически на более широкий маршрут, поэтому трафик перестает проходить. Для создания полноценной резервной пары настройте оба маршрутизатора на анонсирование одних и тех же специфичных префиксов.

Имя хоста разрешается, но соединение прерывается по таймауту. Почему?

DNS-разрешение и маршрутизация — это разные этапы. Имя может разрешаться в адрес, который не покрывается ни одним одобренным маршрутом, и тогда пакет уходит через шлюз по умолчанию на клиенте. Выполните ip route get <address> на клиенте. Если ответ не содержит dev tailscale0, анонсируйте диапазон, который покрывает этот адрес, и одобрите новый префикс в панели администратора.