SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-26

Настройка 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, и ваш ноутбук получит прямой доступ к этим частным адресам. В самом сегменте ничего не меняется, база данных по-прежнему не имеет публичного адреса. Если из этого сегмента вам нужно только одно веб-приложение на одном порту, анонсирование всего диапазона избыточно, и Tailscale serve позволяет настроить HTTPS для этого единственного порта. Тот же подход применим к демону, который намеренно привязан только к localhost, например, dsh, работающий в фоновом режиме под управлением systemd, где адрес в tailnet на этом VPS заменяет SSH-туннель, который иначе пришлось бы держать открытым для доступа к его интерфейсу.

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

Оба случая объединяет одно требование. 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) отключена. Пересылка пакетов других машин — основная задача маршрутизатора подсети, поэтому этот шаг обязателен.

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 срабатывает немедленно, но настройки сбрасываются после перезагрузки. В результате маршрутизатор подсети может работать неделями, а затем перестать функционировать после обновления ядра и перезагрузки системы. Проблема в том, что внешне всё выглядит исправно. В 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 будет отображаться с меткой subnet. Разверните строку с этим узлом, найдите раздел 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 выключенным и используйте только анонсирование.

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

Два подсетевых маршрутизатора не должны анонсировать идентичные диапазоны. Перекрывающиеся диапазоны с разной длиной префикса допустимы, и 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, а ваш подсетевой маршрутизатор анонсирует 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, поэтому правила межсетевого экрана и журналы доступа не содержат информации об исходном клиенте.

Отключите эту функцию в 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, иначе оно будет удалено при следующей загрузке.

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

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

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

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

Наконец, решите, хотите ли вы использовать сервер координации, который вы не контролируете. Control plane Tailscale — это облачный сервис. Ваши ключи остаются на ваших машинах, но учетная запись и файл политик хранятся там. Стоит заранее определить, что именно может произойти в случае компрометации control plane или кражи учетных данных, прежде чем предоставлять доступ к вашей частной сети. Модель доверия Tailscale определяет границы этой ответственности. Стоимость редко является причиной отказа от сервиса, так как бесплатный тариф включает до шести пользователей с неограниченным количеством собственных устройств, хотя subnet router, запущенный под тегом, учитывается иначе, чем узел, авторизованный под вашей учетной записью. После этого лимита оплата рассчитывается по количеству пользователей, а не машин, поэтому сколько на самом деле платят домохозяйства или команды из пяти человек после окончания бесплатного тарифа стоит рассчитать до того, как вы добавите учетную запись, превышающую лимит. Запуск Headscale, self-hosted сервера координации Tailscale позволяет оставить управление на вашем VPS ценой необходимости его обслуживания. Другой вариант решения той же проблемы — отказаться от клиентов Tailscale и развернуть VPN-сервер NetBird, что перенесет уровень координации и собственные mesh-клиенты на одну машину под вашим контролем. Если вы все еще выбираете между этой моделью и конфигурацией вручную, сравнение WireGuard и Tailscale объясняет, что дает уровень координации и какова его цена.

FAQ

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

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

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

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

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

Скорее всего, 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, анонсируйте диапазон, который покрывает этот адрес, и одобрите новый префикс в панели администратора.