SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor

Tailscale serve чи funnel: що вибрати

Tailscale serve відкриває HTTPS-URL лише у tailnet, а funnel робить порт публічним. Дізнайтеся про різницю та політику, що блокує funnel.

tailscale serve проти funnel: хто може отримати доступ до URL

Різниця між tailscale serve і tailscale funnel полягає лише в аудиторії. serve додає HTTPS (hypertext transfer protocol secure) фронтенд до локального порту та публікує його лише у вашому tailnet. funnel публікує той самий локальний порт у всьому публічному інтернеті через relay-сервери, які запускає Tailscale. Обидві команди приймають однакові прапорці та однакові цілі. Одне слово відділяє приватну панель керування від панелі, доступної з усього світу.

В обох випадках ви отримуєте сертифікат, якому браузери вже довіряють, для імені, що закінчується на ts.net. Для жодного варіанта не потрібно відкривати вхідний порт у firewall вашого VPS. Демон tailscaled уже має вихідне з’єднання з tailnet, тому трафік надходить через нього. Підключення сервера до tailnet — окреме завдання. Його описано в матеріалах про використання VPS як exit node Tailscale або оголошення subnet router для приватної мережі. А публікація сервісу, який уже працює в tailnet, — це тема цього розділу.

Що потрібно до виконання будь-якої команди

  • Tailscale 1.38.3 або новішої версії на VPS; користувач має увійти до свого tailnet. Перевірте це за допомогою tailscale version і tailscale status.
  • Увімкнений MagicDNS. MagicDNS — це вбудований DNS (система доменних імен) Tailscale. Він надає машині ім’я, наприклад blog-vps.your-tailnet.ts.net, замість використання лише адреси 100.x.
  • Увімкнені сертифікати HTTPS для tailnet на сторінці DNS в адміністративній консолі. Без цього не буде сертифіката, який можна встановити перед вашим портом.
  • Лише для funnel потрібен атрибут вузла funnel у файлі політики tailnet. Саме на цьому найчастіше зупиняються перші спроби. Нижче описано, як це налаштувати.

Кожна команда тут починається з sudo, оскільки CLI взаємодіє з tailscaled через сокет, до якого має право запису лише root. Надайте одному користувачеві право не вводити цей префікс:

sudo tailscale set --operator=$USER

Публікуйте сервіс у tailnet за допомогою tailscale serve

Укажіть serve локальний порт, і tailscale serve виконає решту налаштувань.

sudo tailscale serve 3000
Available within your tailnet:
https://amelie-workstation.pango-lin.ts.net

 |-- / proxy http://127.0.0.1:3000

Press Ctrl+C to exit.

Скорочений запис 3000 означає http://127.0.0.1:3000. Tailscale прослуховує порт 443 на tailnet-адресі машини, завершує TLS (transport layer security) за допомогою сертифіката ts.net і передає звичайний HTTP на локальний порт. Застосунок не повинен знати про наявність сертифіката. Саме тому цей спосіб зручно використовувати перед панеллю адміністрування, яку інакше довелося б залишити доступною через звичайний HTTP.

Тепер зверніть увагу на останній рядок: Press Ctrl+C to exit. Команда працює у foreground, а зіставлення існує лише в межах цього процесу. Якщо закрити термінал, URL перестане працювати, оскільки конфігурацію не записано на диск. Додайте --bg, і зіставлення буде збережено в конфігурації serve для вузла. Воно переживе закриття термінала та перезавантаження.

sudo tailscale serve --bg 3000

Serve працює не лише з номером порту. --set-path публікує сервіс за subpath, тому кілька застосунків можуть використовувати одне ім’я хоста:

sudo tailscale serve --bg --set-path=/grafana 3000
sudo tailscale serve --bg --set-path=/metrics 9090

Як ціль можна також указати каталог зі статичними файлами або backend, який уже використовує TLS із сертифікатом, перевіряти який не потрібно:

sudo tailscale serve --bg /srv/reports
sudo tailscale serve --bg https+insecure://localhost:8443

Це працює не лише з HTTP. --tcp=<port> передає необроблений потік TCP (transmission control protocol), а --tls-terminated-tcp=<port> завершує TLS на вузлі та передає далі відкритий текст. Так можна розмістити довірений сертифікат перед сервісом, який взагалі не підтримує HTTP:

sudo tailscale serve --bg --tls-terminated-tcp=443 tcp://127.0.0.1:9899

Чому funnel повідомляє, що атрибут вузла не задано?

За замовчуванням Funnel вимкнено для всього tailnet. Під час першого запуску відображається це повідомлення, після чого команда завершується:

Funnel not available; "funnel" node attribute not set. See https://tailscale.com/kb/1223/tailscale-funnel/.

Команду введено правильно. Політика tailnet не надала цьому вузлу дозволу на публікацію, тому клієнт відмовляється ще до підключення до relay. Відредагуйте файл політики tailnet в адміністративній консолі в розділі Access Controls і додайте атрибут:

"nodeAttrs": [
  {
    "target": ["autogroup:member"],
    "attr":   ["funnel"],
  },
],

autogroup:member надає його всім учасникам tailnet. Якщо публікувати має лише один комп’ютер, додайте цьому комп’ютеру tag і натомість призначте атрибут цьому tag, наприклад tag:public. Збережіть політику, а потім знову виконайте команду funnel.

Якщо ваш обліковий запис має права адміністратора tailnet, нові версії клієнта пропонують спрощений спосіб: CLI виводить URL для підтвердження на login.tailscale.com. Перехід за цим URL вмикає HTTPS-сертифікати та додає атрибут. Якщо ви не адміністратор, цей URL не допоможе. Редагування має виконати користувач із доступом до політики.

Опублікувати в інтернеті за допомогою tailscale funnel

Після встановлення атрибута команда має вже знайомий вигляд, але з іншим дієсловом.

sudo tailscale funnel --bg 3000
Available on the internet:
https://amelie-workstation.pango-lin.ts.net

 |-- / proxy http://127.0.0.1:3000

Press Ctrl+C to exit.

Щоразу уважно читайте перший рядок. Available within your tailnet і Available on the internet — це єдина видима відмінність між приватним і публічним сервісом, а команди для їх створення відрізняються одним словом.

Станом на серпень 2026 року funnel прослуховує порти 443, 8443 або 10000 і жодні інші. Портом за замовчуванням є 443, а --https=8443 або --https=10000 — альтернативи. Будь-який інший порт відхиляється, оскільки ретранслятори funnel приймають з’єднання лише на цих портах. Тому URL funnel завжди містить лише ім’я хоста або ім’я хоста з доданим у кінці :8443.

Як переглянути, що зараз опубліковано?

Припущення — причина, через яку dashboard може залишатися публічно доступним протягом місяця. Запитайте сам node.

tailscale serve status
tailscale funnel status
tailscale serve status --json

Обидві команди status читають один і той самий config, тому будь-яка з них показує повну картину. Використовуйте форму --json у скрипті або запланованій перевірці, оскільки звичайний output призначений для читання людьми. Якщо нічого не налаштовано, ви отримаєте один рядок:

No serve config

Якщо після налаштування, яке раніше працювало, ви бачите цей результат, це означає, що mapping було створено у foreground, а процес завершився. Створіть mapping повторно за допомогою --bg.

Щоб видалити один mapping, повторіть команду, якою його було створено, і додайте off в кінці. Щоб видалити всі mapping serve і funnel на node, використовуйте reset.

sudo tailscale funnel --https=443 3000 off
sudo tailscale serve reset

Після будь-якої з цих команд знову виконайте tailscale serve status і перевірте, що залишилося, замість того щоб припускати, що команда зробила саме те, що ви мали на увазі.

Що ви отримуєте і від чого відмовляєтеся

Переваги реальні, і саме тому цей варіант обирають замість reverse proxy.

  • Сертифікат, якому довіряють браузери, поновлюється автоматично. Не потрібно встановлювати ACME (середовище автоматичного керування сертифікатами) client і налаштовувати завдання для поновлення.
  • На firewall VPS не потрібен вхідний порт. tailscaled встановлює вихідне з’єднання, тому firewall ufw на VPS із політикою default-deny може залишатися таким самим суворим.
  • Не потрібно купувати, налаштовувати або чекати на DNS-запис.
  • Не потрібен port forwarding. Це особливо важливо для машини за NAT (трансляцією мережевих адрес), а не для VPS із публічною IP-адресою.

Недоліки так само реальні, і funnel має їх усі.

  • Ім’я не належить вам. Публічні відвідувачі бачать host.your-tailnet.ts.net. Funnel не підтримує custom domain, тому не можна розмістити перед ним app.example.com.
  • Шлях передавання даних не належить вам. Трафік спочатку надходить до relay Tailscale, а relay проксирує потік до вашого node через tailnet. Tailscale зазначає, що на трафік funnel поширюються обмеження пропускної здатності, які не опубліковані й не налаштовуються. Тому виміряйте власну пропускну здатність, перш ніж покладатися на певне значення.
  • Засоби керування відсутні. Reverse proxy, який ви запускаєте самостійно, надає access logs, rate limits, обмеження розміру запитів і місце для налаштування автентифікації. Funnel надає URL. Усе інше має бути реалізовано у вашому застосунку.
  • Список портів фіксований, як зазначено вище.

Обидві функції також залежать від інфраструктури, якою керує Tailscale: видачі сертифікатів для імені ts.net і самих relay funnel. Якщо ви розглядаєте self-hosted control server Headscale, не припускайте, що ці можливості працюватимуть із ним. Перевірте release notes для версії Headscale, яку плануєте запускати.

Який варіант використовувати?

Правило просте.

Використовуйте serve для всього внутрішнього: адміністративних інтерфейсів, дашбордів, інтерфейсу метрик, який не має індексуватися, і staging-копії сайту. Членство в tailnet є контролем доступу, і це надійний варіант. Пристрій, якого немає в tailnet, навіть не зможе розв’язати це ім’я.

Використовуйте funnel для демонстраційного посилання, приймача webhook, якому сторонній сервіс має надсилати POST-запити, або OAuth callback під час розробки. Це найшвидший спосіб отримати публічний HTTPS URL, а однією командою off його можна вимкнути. Але public означає public: hostname не є секретом, а funnel перед застосунком без входу створює відкритий сервіс. Усе, що розміщене за ним, має автентифікувати власні запити з такою самою ретельністю, яка потрібна для відкритого API endpoint Ollama.

Для всього, що ви назвали б production, використовуйте повноцінний reverse proxy. Ваш домен, ваш сертифікат, ваші журнали, ваші rate limits — і жодних інших учасників у ланцюжку обробки запиту. У матеріалі Порівняння nginx, Caddy і Traefik як reverse proxy описано, як вибрати потрібний варіант.

Режими відмови та повідомлення, які ви побачите

Funnel відмовляється запускатися. Funnel not available; "funnel" node attribute not set. — це проблема політики, а не команди. Додайте атрибут funnel до файла політики tailnet, збережіть файл і повторіть спробу.

Все працювало, а тепер tailscale serve status повідомляє No serve config. Відображення було створене у foreground, а потім цей процес завершився. Повторно виконайте ту саму команду з --bg.

Ім’я розпізнається, але відповіді немає. Serve проксирує запити до вказаної вами цілі. Якщо на ній нічого не прослуховує порт, проксирувати запит нікуди. Перевірте це за допомогою ss -ltnp | grep 3000 на тому самому комп’ютері, де запущено tailscaled. Частою причиною є контейнер, який публікує свій порт на адресі Docker bridge замість 127.0.0.1. У такому разі хост не бачить слухача там, де ви його очікуєте. У матеріалі Як працює мережа Docker Compose показано, куди фактично потрапляє опублікований порт.

Помилки сертифіката для імені ts.net. Найімовірніше, HTTPS-сертифікати не ввімкнено для tailnet. Увімкніть їх в адміністративній консолі, а потім запустіть крок отримання сертифіката окремо, щоб його помилки не змішувалися з виводом serve:

sudo tailscale cert your-host.your-tailnet.ts.net

Funnel завантажується через мобільний інтернет, але працює інакше, ніж на ноутбуці. Ваш ноутбук підключений до tailnet, тому MagicDNS розпізнає ім’я як адресу 100.x, і ви напряму підключаєтеся до сервісу, не використовуючи relay. Це очікувана поведінка. Вона означає, що ноутбук не може перевірити доступність сервісу з публічної мережі. Використайте curl на комп’ютері, який не підключений до tailnet.

FAQ

У чому різниця між tailscale serve і tailscale funnel?

Хто може отримати доступ до результату. tailscale serve публікує локальний порт за HTTPS-URL, доступним лише пристроям у вашому tailnet. tailscale funnel публікує той самий порт за URL, доступним будь-кому в інтернеті, через relay-сервери Tailscale. Прапорці та цілі в них спільні. Перший рядок виводу показує, який режим використано: Available within your tailnet або Available on the internet.

Чому tailscale funnel повідомляє, що атрибут вузла не задано?

Тому що funnel вимкнено для tailnet, доки хтось його не ввімкне. Це повідомлення має вигляд Funnel not available; "funnel" node attribute not set. і надходить від вашого клієнта ще до встановлення з’єднання з relay-сервером. Додайте запис nodeAttrs, який надає атрибут funnel об’єкту autogroup:member або тегу, якщо публікувати має лише одна машина, у файлі політики tailnet у розділі Access Controls. Адміністратор tailnet також може перейти за URL підтвердження, який виводить CLI.

Які порти може використовувати Tailscale Funnel?

Лише 443, 8443 і 10000. Типовим є 443, а інший порт можна вибрати за допомогою --https=8443 або --https=10000. Це обмеження relay-серверів funnel, а не вашого сервера, тому зміна firewall або конфігурації на VPS його не скасує. tailscale serve такого обмеження не має, оскільки трафік не виходить за межі вашого tailnet.

Чи зберігається URL serve або funnel після перезавантаження?

Лише якщо ви використали --bg. Без нього команда працює у foreground, виводить Press Ctrl+C to exit., а mapping зникає разом із процесом. З --bg mapping записується в конфігурацію serve вузла та відновлюється за допомогою tailscaled після перезавантаження. Перевірте стан командою tailscale serve status. Якщо нічого не налаштовано, вона виводить No serve config.

Чи безпечно залишати funnel увімкненим?

З погляду транспорту це безпечно: з’єднання використовує HTTPS, і на вашому firewall не відкривається жоден порт. Але це не безпечно у звичному практичному сенсі, оскільки URL є публічним, а отже публічним стає і застосунок за ним. Використовуйте funnel лише перед застосунком, який сам автентифікує запити, і вимикайте його після завершення демонстрації або тестування webhook командою, якою його створено, додавши off в кінці.

Джерела описаної вище поведінки команд: документація Tailscale Serve і Funnel та довідник CLI на tailscale.com/docs.