MagicDNS в Tailscale: имена машин вместо IP
Как обращаться к машинам Tailscale по имени: короткая и полная форма, включение MagicDNS, и почему имя не резолвится на VPS, в Docker и при перехвате порта 53.
Что такое MagicDNS и как выглядит имя машины
MagicDNS выдаёт каждой машине в тейлнете имя, по которому к ней обращаются вместо адреса 100.x. Имя одинаково работает с любого узла сети, не зависит от того, какой IP выдал провайдер, и не меняется, когда ноутбук переехал из дома в кафе. Пока MagicDNS выключен, в вашем распоряжении только адреса вида 100.101.102.103, и их приходится копировать руками в каждый конфиг.
У имени две формы. Короткая совпадает с hostname машины: vps1. Полная добавляет имя тейлнета и общий для всех суффикс: vps1.tail1a2b3.ts.net. Обе указывают на одну машину. Разница в том, что короткая форма резолвится только там, где резолвер получил search-домен вашего тейлнета. В файлах конфигурации, в cron и внутри контейнеров пишите полную форму, потому что search-домен туда чаще всего не доходит.
Имя ничего не добавляет к правам доступа. Оно превращается в тот же адрес из диапазона 100.64.0.0/10, который клиент получил при входе в тейлнет, а кто с кем может соединяться, по-прежнему решают ACL тейлнета. Если вы только знакомитесь с моделью сети, начните с разбора того, что такое Tailscale и из чего состоит тейлнет, а установку клиента и типовые проблемы с пакетом смотрите в руководстве по ошибкам установки Tailscale на Ubuntu.
Откуда берётся имя тейлнета
Имя тейлнета видно в админке на странице DNS, в блоке Tailnet name. У личного аккаунта оно выглядит как tail1a2b3.ts.net, где вместо 1a2b3 стоит случайный набор символов. Придумать его нельзя: значение выдано вашему аккаунту. Во всех примерах ниже tail1a2b3.ts.net надо заменить на своё.
Имя тейлнета можно сменить там же в админке. Делайте это один раз и до того, как имена разойдутся по конфигам. Смена имени тейлнета меняет полное имя каждой машины сразу, и всё, что ссылалось на старое имя (~/.ssh/config, docker compose, мониторинг), перестаёт резолвиться.
Короткая часть имени берётся из hostname машины: буквы приводятся к нижнему регистру, а символы, недопустимые в DNS, заменяются на дефис. Машина с hostname My_Laptop получает имя my-laptop. Если в тейлнете уже есть машина с таким именем, Tailscale добавляет к новой числовой суффикс, поэтому три сервера, развёрнутые из одного образа с hostname ubuntu, получат три похожих, но разных имени. Это первая причина задать серверу осмысленный hostname до входа в тейлнет.
Что происходит со старым именем при переименовании машины
Переименовать машину можно с самого узла или из админки. На узле это две команды: sudo hostnamectl set-hostname web-01 меняет hostname системы, а sudo tailscale set --hostname=web-01 заставляет клиент сообщить новое имя координационному серверу. В админке нужный пункт лежит в разделе Machines, в меню конкретной машины. Имя, заданное вручную в админке, дальше держится вручную и не перезаписывается тем hostname, который сообщает операционная система.
Старое имя после переименования просто перестаёт существовать. Редиректа нет, алиаса нет, запрос по старому имени возвращает отрицательный ответ. Резолверы помнят отрицательный ответ какое-то время, поэтому сразу после переименования сбросьте кэш: на Linux с systemd-resolved это sudo resolvectl flush-caches. Затем посмотрите, что выводит tailscale status на любой другой машине тейлнета: в строке этого узла будет то имя, которое сейчас действует.
Адрес 100.x, который работает, когда DNS не работает
tailscale ip -4
tailscale statustailscale ip -4 печатает адрес текущей машины. tailscale status выводит по строке на каждый узел тейлнета, с его именем и адресом. Посмотрите, что показывают обе команды у вас: это и есть те адреса, в которые в итоге превращается любое имя MagicDNS.
Адрес закреплён за машиной на всё время, пока она числится в тейлнете. Он не зависит от DNS вообще, потому что маршрутизация внутри Tailscale построена на этих адресах, а имя подставляется на шаг раньше, при разрешении. Отсюда главная диагностическая проверка всей статьи: если ping по адресу 100.x проходит, а по имени соединение не устанавливается, то тоннель исправен и проблема целиком в DNS. Дальше нужно только понять, на каком шаге теряется имя.
Два выключателя MagicDNS: тейлнет и отдельный узел
Имя чаще всего не резолвится потому, что один из двух выключателей стоит в положении «выключено». Первый общий для всей сети: в админке на странице DNS должен быть включён MagicDNS. Второй свой у каждого узла: клиент должен принимать DNS-настройки от тейлнета.
sudo tailscale set --accept-dns=true
tailscale dns statusПервая команда включает приём настроек на этом узле. Вторая в свежих версиях клиента печатает, какой резолвер и какие домены сейчас применены. Посмотрите, что она показывает на вашей машине, и есть ли там адрес 100.100.100.100 вместе с доменом вашего тейлнета. Если команда не поддерживается вашей версией, то же состояние видно в выводе tailscale debug prefs в поле CorpDNS.
На серверах второй выключатель часто выключен намеренно. Тот, кто ставил клиент, добавил --accept-dns=false, чтобы Tailscale не трогал DNS на машине с собственным резолвером. Тогда MagicDNS на этой машине не работает по определению. Включать флаг обратно не обязательно: можно оставить свой резолвер и направить в нём зону ts.net на 100.100.100.100.
Почему имя не резолвится на VPS, хотя на ноутбуке работает
Адрес 100.100.100.100 обслуживает не удалённый сервер, а демон tailscaled на вашей же машине. Он отвечает на запросы об именах тейлнета из карты сети, которую уже держит в памяти. Чтобы система спрашивала именно его, tailscaled должен встроиться в цепочку разрешения имён. На Linux есть два пути: через systemd-resolved по D-Bus, когда клиент привязывает к интерфейсу tailscale0 резолвер 100.100.100.100 и домен тейлнета, или прямой правкой /etc/resolv.conf, если resolved не используется.
В образах VPS эта цепочка рвётся по трём типовым причинам:
- systemd-resolved не запущен,
tailscaledпишет в/etc/resolv.confнапрямую, а cloud-init, netplan илиresolvconfпереписывают файл обратно при следующей перенастройке сети. Настройка исчезает, и ни одного сообщения об ошибке при этом не появляется. /etc/resolv.confоказался обычным файлом, а не символической ссылкой на/run/systemd/resolve/stub-resolv.conf. Resolved при этом работает, но система его не спрашивает, поэтому то, что Tailscale передал в resolved, до запросов не доходит.- в минимальном образе нет D-Bus, и клиент не может сообщить resolved о новом интерфейсе.
resolvectl status tailscale0
ls -l /etc/resolv.conf
resolvectl query vps1.tail1a2b3.ts.netПосмотрите, что показывает resolvectl status tailscale0: в этом блоке перечислены DNS-сервер и домены, привязанные к интерфейсу. ls -l /etc/resolv.conf скажет, файл это или ссылка. resolvectl query пройдёт весь системный путь разрешения имени и напечатает, чем он закончился.
Теперь разделяющая проверка. Спросите резолвер Tailscale напрямую, в обход системного пути.
sudo apt install -y bind9-dnsutils
dig @100.100.100.100 vps1.tail1a2b3.ts.net +shortСравните два результата. Если прямой запрос к 100.100.100.100 возвращает адрес, а resolvectl query с тем же именем не возвращает, то MagicDNS исправен и сломан системный путь: занимайтесь /etc/resolv.conf и systemd-resolved. Если пустой ответ даёт и прямой запрос, дело в самом тейлнете: MagicDNS выключен в админке, узел не принимает DNS, или машины с таким именем в сети сейчас нет.
Привести систему в рабочее состояние на Ubuntu можно так:
sudo systemctl enable --now systemd-resolved
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo tailscale set --accept-dns=true
sudo systemctl restart tailscaledВторую строку выполняйте только если DNS на этой машине действительно должен управляться systemd-resolved. На VPS со своим unbound или dnsmasq эта же строка сломает разрешение имён целиком, и чинить придётся уже её.
Почему имя не резолвится внутри Docker контейнера
Причина в том, как Docker готовит /etc/resolv.conf для контейнера. Демон берёт файл хоста и выбрасывает из него адреса на localhost, потому что внутри контейнера 127.0.0.53 указывает на сам контейнер, а не на хост. На Ubuntu с systemd-resolved в файле хоста стоит именно 127.0.0.53, поэтому выбрасывается всё, и Docker подставляет публичные резолверы. Публичный резолвер про ваш тейлнет ничего не знает, поэтому имя возвращается как несуществующее, хотя на хосте то же самое имя резолвится нормально.
Лечится это тем, что резолвер и search-домен задаются контейнеру явно.
docker run --rm --dns 100.100.100.100 --dns-search tail1a2b3.ts.net alpine:3.21 ping -c 3 vps1То же самое в compose:
services:
app:
image: alpine:3.21
dns:
- 100.100.100.100
dns_search:
- tail1a2b3.ts.netУсловие одно: пакеты из контейнера должны доходить до 100.100.100.100. На обычной bridge-сети они уходят через хост, а хост направляет их в интерфейс tailscale0, и это работает. На сети, объявленной как internal: true, выхода на хост нет, и запрос не дойдёт никуда. Как устроены такие сети, подробно разобрано в описании сетей docker compose. Второй рабочий вариант: поднять клиент Tailscale отдельным контейнером и пускать сервисы через его сетевой стек, что описано в запуске Tailscale в docker compose.
Что делает перехват порта 53 роутером или провайдером
Если ваш роутер или провайдер заворачивает весь трафик на 53 порт на свой резолвер, на имена .ts.net это не влияет. Запрос к 100.100.100.100 обслуживает локальный демон, ответ собирается из карты сети, и пакет с этим запросом не покидает машину. Перехватывать там нечего.
Ломается вторая половина работы MagicDNS. Запросы, которые не относятся к тейлнету, Tailscale пересылает вышестоящим резолверам из раздела Global nameservers, и вот они уходят в сеть по 53 порту. Если в админке включена опция Override local DNS, через них идёт вообще всё разрешение имён на машине. Симптом узнаваемый: ssh vps1.tail1a2b3.ts.net работает, а обычные сайты резолвятся неправильно, медленно или не резолвятся совсем.
Есть два способа развести эти случаи. Первый: указать в Global nameservers известный публичный резолвер. Для таких резолверов клиент Tailscale использует DNS поверх HTTPS, то есть 443 порт, и перехват 53 перестаёт на что-либо влиять. Второй: оставить Override local DNS выключенным, если вам нужны только имена тейлнета. Тогда зону ts.net обслуживает MagicDNS, а всё остальное идёт через резолвер локальной сети, каким бы он ни был.
Отдельно в админке живёт Split DNS: конкретный домен можно отправить на конкретный резолвер внутри тейлнета, например внутреннюю зону компании на сервер, доступный только по Tailscale. Ради этого люди и поднимают приватный DNS для внутренних имён, только здесь не нужен свой сервер на каждой площадке. Помните ещё, что при включённом выходном узле на VPS DNS-запросы идут через этот узел, поэтому результаты могут отличаться от того, что даёт та же машина без него.
Если вы пришли сюда от чистого WireGuard, сравните подходы в разборе DNS поверх WireGuard: механика та же, но строку DNS = там вы пишете руками и сами отвечаете за утечки. А если зависеть от чужого координационного сервера не хочется, те же имена и ту же схему разрешения даёт Headscale, развёрнутый на своём VPS.
Запись в ~/.ssh/config вместо скопированного IP
Ради этого всё и затевалось. Вместо ssh deploy@100.101.102.103 в конфиг попадает имя, а вы работаете с коротким алиасом.
Host vps1
HostName vps1.tail1a2b3.ts.net
User deploy
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30Host задаёт алиас, который вы набираете в терминале. HostName задаёт имя, которое ssh передаёт резолверу. Дальше достаточно ssh vps1, и адрес машины больше нигде у вас не записан, поэтому его смена ничего не ломает. Первое подключение по новому имени добавит запись в ~/.ssh/known_hosts, так что ssh один раз спросит подтверждение отпечатка ключа. Сверьте его с тем, что выводит ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub на самом сервере.
Рядом держите запасной блок с адресом:
Host vps1-ip
HostName 100.101.102.103
User deploy
IdentityFile ~/.ssh/id_ed25519Когда имя перестанет резолвиться, а это случается после обновления клиента, перезагрузки VPS или правки сетевых настроек, вы войдёте по адресу и почините DNS изнутри. Адрес 100.x для этого и годится: он не зависит от DNS. Именно такая схема позволяет закрыть 22 порт снаружи и вообще перестать пробрасывать порты на роутере. Если на сервере включить sudo tailscale set --ssh, доступом начнут управлять ACL тейлнета вместо authorized_keys, но запись в ~/.ssh/config от этого не становится лишней: имя вы всё равно набираете.
Порядок проверки, когда имя не резолвится
tailscale statusна обеих машинах: нужный узел вообще есть в списке и не помечен как offline.- Пинг по адресу из
tailscale ip -4: если он проходит, тоннель исправен и дальше вы чините только DNS. tailscale dns statusна проблемной машине: видно, применены ли настройки MagicDNS.dig @100.100.100.100 vps1.tail1a2b3.ts.net +short: отделяет проблему тейлнета от проблемы системного резолвера.- Полное имя вместо короткого: если полное работает, а короткое нет, то до резолвера не дошёл search-домен.
- Адрес 100.x во временный блок
~/.ssh/config, чтобы попасть на машину и продолжить разбор с неё.
FAQ
Почему имя MagicDNS резолвится на ноутбуке, но не на VPS?
На ноутбуке клиент Tailscale обычно настраивает DNS сам и целиком, а на сервере в эту же цепочку встроены systemd-resolved, cloud-init и netplan. Типовых причин три: на узле стоит --accept-dns=false, /etc/resolv.conf оказался обычным файлом вместо ссылки на /run/systemd/resolve/stub-resolv.conf, или сторонний менеджер сети переписал файл после tailscaled. Чтобы понять, куда смотреть, сравните dig @100.100.100.100 <имя> и resolvectl query <имя>: если прямой запрос отвечает, а системный нет, чинить надо резолвер системы, а не Tailscale.
Как узнать полное имя машины и имя своего тейлнета?
Имя тейлнета показано в админке на странице DNS, в блоке Tailnet name, и выглядит как tail1a2b3.ts.net со случайной частью. Полное имя машины складывается из её hostname в нижнем регистре и этого суффикса. Проверить, под каким именем машина сейчас числится, можно командой tailscale status с любого другого узла тейлнета: там перечислены имена и адреса всех машин.
Что будет со старым именем, если переименовать машину?
Старое имя перестаёт резолвиться, и ничего не перенаправляет запросы на новое. Всё, что ссылалось на старое имя, перестаёт работать: записи в ~/.ssh/config, dns_search в compose, адреса в системе мониторинга. Отрицательный ответ ещё какое-то время живёт в кэшах, поэтому после переименования сбросьте кэш командой sudo resolvectl flush-caches на клиентах с systemd-resolved.
Почему имя машины не резолвится внутри Docker контейнера?
Docker копирует /etc/resolv.conf хоста в контейнер, но выбрасывает адреса на localhost, потому что внутри контейнера они указывают на него самого. На Ubuntu с systemd-resolved там стоит 127.0.0.53, и после его удаления Docker подставляет публичные резолверы, которые про ваш тейлнет ничего не знают. Запустите контейнер с --dns 100.100.100.100 и --dns-search <ваш тейлнет>.ts.net, либо задайте те же ключи dns и dns_search в compose.