Tailscale 筆記

發布於 2026-08-12 00:00 5488 字 28 min read

丁丁 avatar

丁丁

隨意寫寫,筆記記錄,以免忘記,後悔莫及

Tailscale 筆記 想從外面連回家裡的 NAS、路由器管理頁、或是那台跑著一堆服務的小主機,傳統做法是在路由器上開通訊埠轉發 (Port forwarding)、自架 OpenVPN 或 WireGuard,然後跟浮動 IP、NAT、防火牆規則搏鬥半天。 Tailscale 把這件事變成「裝一個軟體、登入、結束」。它底層就是 WireGuard,但把最麻煩的金鑰交換、NAT...

Tailscale 筆記

前言

想從外面連回家裡的 NAS、路由器管理頁、或是那台跑著一堆服務的小主機,傳統做法是在路由器上開通訊埠轉發 (Port forwarding)、自架 OpenVPN 或 WireGuard,然後跟浮動 IP、NAT、防火牆規則搏鬥半天。

Tailscale 把這件事變成「裝一個軟體、登入、結束」。它底層就是 WireGuard,但把最麻煩的金鑰交換、NAT 穿透、裝置探索全部自動化了。你不需要開任何對外通訊埠,裝置之間會自己想辦法直連。

這篇是我的設定筆記,涵蓋安裝、常用指令、子網路由 (Subnet Router)、出口節點 (Exit Node)、Tailscale SSH、MagicDNS、Tailscale Services,以及 Docker 部署方式。

核心概念

先把名詞搞清楚,後面看設定會順很多。

名詞意思
Tailnet你的私有網路,一個帳號一個 tailnet,所有裝置都在裡面
節點 (Node)加入 tailnet 的裝置,每台會拿到一個 100.x.y.z 的固定 IP
控制平面 (Control Plane)Tailscale 的協調伺服器,負責交換公鑰與裝置清單。不處理你的流量
DERP中繼伺服器。直連失敗時流量走這裡,仍然是端對端加密
子網路由 (Subnet Router)讓一台節點代理整個內網網段,其他裝置不用每台都裝 Tailscale
出口節點 (Exit Node)把所有對外流量都導到某個節點出去,等同傳統 VPN 的用法
MagicDNS自動幫每台節點配一個名字,直接用 hostname 連線
Service與裝置解耦的具名服務,有自己的虛擬 IP (TailVIP) 與 MagicDNS 名稱
ACL / Tailnet Policy File存取控制規則,用 JSON 描述誰能連到誰

控制平面只負責交換金鑰與裝置資訊,實際流量是節點之間直接走 WireGuard 加密隧道。就算 Tailscale 的伺服器被入侵,對方也解不開你的流量內容。不放心的話可以自架 Headscale 取代控制平面。

安裝

Linux

主流發行版(Ubuntu、Debian、RHEL、CentOS、Fedora、Raspberry Pi OS、Amazon Linux、openSUSE、Oracle Linux)直接用官方腳本:

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

裝完啟動並登入:

sudo tailscale up

終端機會印出一個授權網址,用瀏覽器開啟並登入即可。裝置隨即出現在後台的 Machines 頁面。

確認狀態:

tailscale ip        # 看自己的 tailnet IP
tailscale status    # 看所有節點與連線方式

tailscale status 的輸出裡要特別注意最後一欄:direct 代表 P2P 直連,relay "xxx" 代表流量正在走 DERP 中繼。

其他平台

平台安裝方式
Windows官方 .exe / winget
macOSApp Store 版或獨立版 .pkg
iOS / iPadOSApp Store
AndroidGoogle Play
Synology / QNAP官方套件(Synology 需從 Tailscale 官網下載 .spk
OPNsense / pfSense內建套件庫

macOS 有兩種版本:App Store 版獨立版 (Standalone)。獨立版才支援出口節點與子網路由等進階功能,App Store 版功能受 sandbox 限制。要當 Exit Node 的話請裝獨立版。

常用指令

tailscale status              # 節點清單與連線狀態
tailscale ip -4               # 只看 IPv4
tailscale ping <node>         # 測試對某節點的連線路徑(會顯示 direct 還是 relay)
tailscale netcheck            # 檢查本機 NAT 型態與各 DERP 延遲
tailscale down                # 斷線但保留登入狀態
tailscale up                  # 重新連線
tailscale logout              # 登出並從 tailnet 移除
tailscale file cp <file> <node>:  # 傳檔案到另一台節點
tailscale bugreport           # 產生診斷識別碼,回報問題時用

tailscale ping 跟系統的 ping 不一樣。它會沿著 WireGuard 路徑測試,並告訴你這條連線是直連還是走中繼,排查速度問題的第一個工具就是它。

set 與 up 的差別

新版 Tailscale 把「修改設定」跟「連線」拆開了:

  • tailscale up:連線。加上旗標時會重設未指定的設定
  • tailscale set:只改指定的那一項設定,其他保持不動

所以要調整既有節點的設定,用 tailscale set 比較安全,不會意外把之前的旗標清掉。

子網路由 (Subnet Router)

情境:家裡有一台伺服器、一台 NAS、一台路由器、幾台 IoT 裝置。不可能每台都裝 Tailscale(IoT 裝置根本裝不了),這時候就在其中一台 Linux 機器上開子網路由,讓它代理整個 192.168.1.0/24

1. 開啟 IP 轉送

這步很容易忘,忘了就是「設定看起來都對但連不通」。

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

沒有 /etc/sysctl.d/ 目錄的系統,寫進 /etc/sysctl.confsudo sysctl -p /etc/sysctl.conf

2. 宣告路由

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

多個網段用逗號分隔:--advertise-routes=192.168.1.0/24,10.0.0.0/16

3. 在後台核准路由

宣告完不會馬上生效。到後台 Machines 頁面,該節點會出現 subnets 標記,點進去 → SubnetsEdit → 勾選要核准的路由 → Save

想跳過手動核准,在 Policy File 裡設 autoApprovers

{
  "autoApprovers": {
    "routes": {
      "192.168.1.0/24": ["autogroup:admin"]
    }
  }
}

4. 用戶端接受路由

Linux 用戶端預設不接受子網路由,要手動開:

sudo tailscale set --accept-routes

Windows、macOS、iOS、Android 會自動探索路由,不用額外設定。

5. 設定存取控制

Policy File 裡授權誰可以連進這個網段:

{
  "grants": [{
    "src": ["group:dev"],
    "dst": ["192.168.1.0/24"],
    "ip": ["*:*"]
  }]
}

保留來源 IP

預設子網路由會做 SNAT,內網機器看到的來源 IP 是子網路由那台。想保留原始來源 IP:

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

代價是內網那些機器需要有一條回到 100.64.0.0/10 的路由,否則封包出不去。通常要在路由器上加靜態路由。

子網路由那台機器如果關機,整個網段就都連不到了。重要環境建議開兩台做高可用:兩台宣告相同的路由並都核准,Tailscale 會自動容錯切換。

出口節點 (Exit Node)

子網路由是「連進特定網段」,出口節點是「所有對外流量都從那台出去」,等於傳統 VPN 的用法。適合在外面用公共 Wi-Fi 時把流量繞回家裡。

宣告為出口節點

前提一樣要先開 IP 轉送(見上一節)。

sudo tailscale set --advertise-exit-node

然後到後台該節點的設定裡核准 exit node。用 firewalld 的系統要額外允許 masquerade:

sudo firewall-cmd --permanent --add-masquerade

使用出口節點

sudo tailscale set --exit-node=<節點名稱或IP>

問題來了:一旦啟用出口節點,連本地區域網路都會被導走,家裡的印表機就找不到了。要保留本地存取:

sudo tailscale set --exit-node=<節點名稱或IP> --exit-node-allow-lan-access=true

關閉:

sudo tailscale set --exit-node=

Policy File 需要授權 autogroup:internet

{
  "grants": [{
    "src": ["group:dev"],
    "dst": ["autogroup:internet"],
    "ip": ["*:*"]
  }]
}

每台裝置都必須主動選擇要使用出口節點,不會被強制套用。這是刻意的設計——避免管理員一改設定就把所有人的流量全部繞道。

MagicDNS

啟用後每台節點自動獲得 <hostname>.<tailnet-name>.ts.net 的名字,同一個 tailnet 內直接用 hostname 就能連,不用背 100.x.y.z

後台 DNS 頁面 → 勾選 Enable MagicDNS

Linux 用戶端要接受 DNS 設定:

sudo tailscale set --accept-dns

改主機名稱:

sudo tailscale set --hostname=nas

MagicDNS 會接管 /etc/resolv.conf。跟本機已經在跑的 DNS 服務(Pi-hole、AdGuard Home、dnsmasq、systemd-resolved 的某些設定)容易打架。

如果那台機器本身就是你的 DNS 伺服器,建議關掉該節點的 --accept-dns,改在後台 DNS 頁面把它設成 tailnet 的 Global nameserver——這樣所有節點都能用你的 Pi-hole 過廣告。

Tailscale SSH

Tailscale 可以接管 port 22,用 tailnet 身分驗證取代 SSH 金鑰。好處是不用再手動散發公鑰、離職成員的存取權在後台一鍵撤銷。

目標主機上啟用:

sudo tailscale set --ssh

Policy File 加上 ssh 區塊(沒有這段的話連不上):

{
  "ssh": [{
    "action": "accept",
    "src": ["autogroup:member"],
    "dst": ["autogroup:self"],
    "users": ["autogroup:nonroot", "root"]
  }]
}

連線就跟平常一樣:

ssh nas
ssh ubuntu@nas

action 除了 accept 還可以設 check,會要求連線者先在瀏覽器完成一次身分再驗證,適合用在生產環境的機器上。

啟用 Tailscale SSH 後,從 tailnet 進來的 22 埠流量會被 tailscaled 攔截,不再交給 sshd。設定 ACL 之前先確認你還有另一條進入路徑(本機終端機、實體存取、或走非 tailnet IP 的 SSH),不然 ACL 寫錯就把自己鎖在門外了。

Serve 與 Funnel

Serve:把本機服務用 HTTPS 分享給 tailnet 內部,自動配憑證。

tailscale serve --bg 3000              # 把 localhost:3000 掛到 https://<host>.<tailnet>.ts.net
tailscale serve status                 # 看目前設定
tailscale serve reset                  # 清掉全部設定

Funnel:把服務開放到整個網際網路,不需要用戶端。

tailscale funnel --bg 3000
tailscale funnel status
tailscale funnel off

Funnel 是真的對全世界開放,Tailscale 不會幫你加任何驗證。只適合本來就打算公開的東西(webhook 接收端、給別人看的 demo)。管理後台、資料庫、任何有敏感資料的服務都不要用 Funnel。

Tailscale Services

Serve 有個先天限制:服務綁在裝置上。網址是 https://nas.<tailnet>.ts.net,機器換掉、服務搬家,網址就跟著變。

Tailscale Services 解決的就是這件事——把服務從裝置上剝離,變成一個獨立的實體。每個 Service 會拿到自己的 TailVIP(虛擬 IP,IPv4 + IPv6 各一)與 MagicDNS 名稱 <service-name>.<tailnet>.ts.net,跟節點一樣是一等公民。底下由哪台機器提供服務、有幾台在提供,使用者完全不需要知道。

比較ServeServices
位址綁定裝置的 MagicDNS 名稱服務自己的 TailVIP 與名稱
搬遷網址跟著變網址不變
多台提供不行可以,自動導流與容錯
ACL 目標tag:server 等節點識別svc:web-server
適合單機的個人服務需要穩定位址、會搬遷或要做高可用的服務

需求:Tailscale v1.86.0 以上。提供服務的主機必須使用標籤身分 (tag),不能是綁在個人帳號下的節點——所以要先 tailscale up --advertise-tags=tag:server

用戶端 v1.94 以上會自動探索 Services,不用設定。v1.93 以下的 Linux 用戶端要 sudo tailscale set --accept-routes

1. 在後台定義 Service

Services → Advertise → Add Service,填入:

  • 服務名稱(會變成 svc:<name> 與 MagicDNS 名稱)
  • 說明
  • 通訊埠與通訊協定,例如 tcp:443
  • 選填標籤,用來在 ACL 裡分組

2. 在主機上設定端點

一行指令同時完成設定與宣告:

tailscale serve --service=svc:web-server --https=443 127.0.0.1:8080

HTTPS 端點的 TLS 憑證由 Tailscale 自動簽發與續期。

端點分三層,依需求選:

L7(應用層)——http / https。支援路徑分流、身分注入:

tailscale serve --service=svc:app --https=443 --set-path=/api localhost:8081

L4(傳輸層)——tcp / tls-terminated-tcp。純 TCP 轉送,不改封包,額外負擔比 L7 低,但不支援 --set-path

tailscale serve --service=svc:db --tcp:5432 tcp://localhost:5432

L3(網路層)——僅 Linux,不管通訊協定的 IP 轉送,保留封包邊界,可搭配 OS 層 iptables 設定支援 UDP:

tailscale serve --service=svc:custom --tun

3. 後台核准

管理員到 Services 頁面把待審的宣告按 Approve。要免手動核准,在 Policy File 設 autoApprovers

{
  "autoApprovers": {
    "services": {
      "svc:web-server": ["tag:server"],
      "tag:prod-service": ["tag:prod-infra"]
    }
  }
}

4. 設定存取控制

Service 可以直接當 dst,比對節點寫 ACL 乾淨很多:

{
  "grants": [
    {
      "src": ["autogroup:member"],
      "dst": ["svc:web-server"],
      "ip": ["443"]
    },
    {
      "src": ["tag:prod-service"],
      "dst": ["svc:database"],
      "ip": ["5432"]
    }
  ]
}

設定檔方式

要管理多個 Service,或想把設定納入版控,用 JSON 設定檔比一行行敲指令好維護。

serveconfig.json

{
  "version": "0.0.1",
  "services": {
    "svc:web-server": {
      "endpoints": {
        "tcp:443": "https://localhost:443"
      },
      "advertised": true
    }
  }
}
欄位必填說明
version目前固定為 "0.0.1"
services服務定義,鍵為 svc:<name>
endpoints協定:通訊埠 對應到本機目標,例如 "tcp:443"
advertised是否接受連線,預設 true

套用與宣告:

tailscale serve set-config --all serveconfig.json
tailscale serve advertise svc:web-server

設定檔方式是「設定」與「宣告」兩步分離,比 CLI 一行搞定更可控——可以先把設定推上去,確認無誤再宣告。

維運指令

tailscale serve status --json                              # 看目前設定
tailscale serve drain svc:web-server                       # 排空:停收新連線,既有連線繼續處理
tailscale serve --service=svc:web-server --https=443 off   # 移除單一端點
tailscale serve clear svc:web-server                       # 清掉該服務全部端點
tailscale serve advertise svc:web-server                   # 改完設定檔後重新宣告

確認本機是否為 service host:

tailscale status --json | jq '.Self.CapMap."service-host"'

服務狀態在後台可以看到:Pending approval(待核准)、Needs configuration(設定有誤或缺漏)、Connected(至少一台在提供)、Offline(沒有主機在宣告)、Pre-approved(已預先核准但還沒宣告)、Draining(排空中)。

高可用與滾動更新

多台主機宣告同一個 Service 時,Tailscale 會自動把流量導到可用的主機。想在同區域內做負載平衡,要另外在 tailnet 開啟 regional routing

drain 讓滾動更新變得很單純:

# 在要下線維護的主機上
tailscale serve drain svc:web-server
# 等既有連線收乾,做你的維護
# 完成後重新宣告
tailscale serve advertise svc:web-server

Services 目前的限制:

  • 只支援 TCP。UDP 僅能透過 Linux 的 L3 端點加上手動 OS 設定實現
  • 只能接收連線。TailVIP 不能主動發起對外連線
  • 保留封包邊界只有 Linux 有
  • 設定檔不支援 text:file: 目標,那兩種只能用 CLI
  • 主機有多張網路介面、且遠端目標不在預設路由表裡時,Linux(缺少 SO_MARK)與 macOS App Store 版可能連不到遠端資源。變通做法是改用 userspace networking 模式

Docker 部署

官方映像檔是 tailscale/tailscale。有兩種常見用法。

事前準備:Auth Key

容器裡沒辦法互動式登入,要先在後台 Settings → Keys 產生一個 Auth Key。建議勾選:

  • Reusable:需要重建容器時不用一直換 key
  • Ephemeral:容器離線後自動從 tailnet 移除節點,避免後台一堆殭屍裝置
  • Tags:綁定 tag:container 之類的標籤,方便寫 ACL

用法一:獨立節點 + 子網路由

讓容器本身當一個節點,順便代理 Docker 網段。

services:
  tailscale:
    image: tailscale/tailscale:latest
    hostname: docker-host
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxx
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_ROUTES=172.20.0.0/16
      - TS_EXTRA_ARGS=--advertise-exit-node
      - TS_USERSPACE=false
    volumes:
      - ./tailscale-state:/var/lib/tailscale
    devices:
      - /dev/net/tun:/dev/net/tun
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    restart: unless-stopped

用法二:Sidecar 模式

讓某個服務只透過 Tailscale 存取,完全不開對外通訊埠。關鍵是 network_mode: service:tailscale,讓服務共用 Tailscale 容器的網路命名空間。

services:
  tailscale:
    image: tailscale/tailscale:latest
    hostname: my-app
    environment:
      - TS_AUTHKEY=tskey-auth-xxxxx
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/serve.json
    volumes:
      - ./tailscale-state:/var/lib/tailscale
      - ./serve.json:/config/serve.json:ro
    restart: unless-stopped

  app:
    image: nginx:alpine
    network_mode: service:tailscale
    depends_on:
      - tailscale
    restart: unless-stopped

serve.json 讓 Tailscale 直接處理 HTTPS:

{
  "TCP": { "443": { "HTTPS": true } },
  "Web": {
    "${TS_CERT_DOMAIN}:443": {
      "Handlers": { "/": { "Proxy": "http://127.0.0.1:80" } }
    }
  }
}

這樣 app 完全沒有對外通訊埠,只有 tailnet 內連得到 https://my-app.<tailnet>.ts.net

用法三:官方 Docker Compose 範例

官方文件的入門寫法,最單純:Tailscale 容器獨立跑,服務容器照舊 publish 埠到 host。

步驟:

  1. 到後台 Settings → Keys 產生 Auth Key,複製起來(只會顯示一次)
  2. 建立 docker-compose.yml,把 <tskey-YOUR-AUTH-KEY> 換成剛剛的金鑰
  3. docker compose up -d
  4. 到後台 Machines 確認 tailscale-nginx 已加入 tailnet
  5. 從 tailnet 上任一裝置連 Docker host 的 8080
services:
  tailscale:
    image: tailscale/tailscale:latest
    container_name: tailscale
    hostname: tailscale-nginx
    environment:
      - TS_AUTHKEY=<tskey-YOUR-AUTH-KEY>
      - TS_STATE_DIR=/var/lib/tailscale
    volumes:
      - ./tailscale-state:/var/lib/tailscale
    cap_add:
      - net_admin
      - net_raw
    restart: unless-stopped

  nginx:
    image: nginx:latest
    container_name: nginx_server
    ports:
      - "8080:80"
    depends_on:
      - tailscale
    restart: unless-stopped

只有兩個環境變數:TS_AUTHKEY 認證、TS_STATE_DIR 搭配 volume 保存狀態。net_adminnet_raw 讓容器能建立 tun 介面走核心態網路,不加的話只能跑 userspace 模式,效能較差。

這個範例裡 nginx 是ports 開在 Docker host 上的,跟 Tailscale 容器沒有共用網路。也就是說:它同時對 host 所在的實體區域網路開放,不是只有 tailnet 連得到。

拿來熟悉流程很好,正式用要收緊的話:

  • 想要只有 tailnet 連得到 + 自動 HTTPS → 改用用法二的 sidecar
  • 想讓 tailnet 直接連容器 IP、完全不開 host 埠 → 改用用法一的子網路由
用法曝露範圍位址適合
一:獨立節點+子網路由只有 tailnet容器 IP,例如 172.20.0.5:8080服務多、想省節點數
二:Sidecar只有 tailnethttps://<name>.<tailnet>.ts.net要 HTTPS、要穩定名稱
三:官方入門範例tailnet host 區網Docker host IP + 埠練習、內網本來就可信任

官方的範例集在 tailscale-dev/docker-guide-code-examples,除了 nginx 還有 OAuth 認證、Mealie、Immich(含 GPU)、Actual Server 等完整範例,也附了一份 example-acls.hujson。Podman 可以直接套用不用改。

常用環境變數

變數用途預設值
TS_AUTHKEY加入 tailnet 的授權金鑰未設定
TS_HOSTNAME節點在 tailnet 的名稱自動產生
TS_STATE_DIR狀態存放目錄,一定要掛 volume未設定
TS_ROUTES宣告子網路由未設定
TS_USERSPACE使用者空間網路模式true
TS_ACCEPT_DNS接受後台的 DNS 設定不接受
TS_SERVE_CONFIGServe / Funnel 設定的 JSON 檔未設定
TS_AUTH_ONCE只認證一次,而非每次啟動都認證false
TS_DEST_IP把進來的 tailnet 流量全部轉給某個 IP未設定
TS_TAILNET_TARGET_IP反向:把流量代理到 tailnet 內某個 IP未設定
TS_TAILNET_TARGET_FQDN同上,用 MagicDNS 名稱指定未設定
TS_SOCKS5_SERVER開 SOCKS5 代理的位址與通訊埠未設定
TS_ENABLE_HEALTH_CHECK開啟 /healthz 端點未啟用
TS_EXTRA_ARGS附加給 tailscale up 的旗標未設定
TS_TAILSCALED_EXTRA_ARGS附加給 tailscaled 的旗標未設定
TS_EXPERIMENTAL_SERVICE_AUTO_ADVERTISEMENT啟動時自動宣告 Tailscale Servicestrue

TS_STATE_DIR 沒有掛 volume 的話,每次重建容器都會被視為全新裝置重新加入 tailnet。後台會累積一堆同名節點(my-app-1my-app-2…),MagicDNS 名稱也跟著跑掉。

TS_USERSPACE 預設是 true,這種模式不需要 NET_ADMIN/dev/net/tun,但效能較差、也不能當子網路由或出口節點。要做這兩件事就得設 TS_USERSPACE=false 並補上 cap_adddevices

容器提供 Service

Sidecar 模式搭配 Tailscale Services 是很順的組合——容器本來就是會被重建、會換機器的東西,正好需要一個與裝置解耦的位址。

TS_SERVE_CONFIG 指向 Service 格式的設定檔即可:

{
  "version": "0.0.1",
  "services": {
    "svc:web-server": {
      "endpoints": {
        "tcp:443": "http://127.0.0.1:80"
      }
    }
  }
}

容器啟動時會自動宣告(由 TS_EXPERIMENTAL_SERVICE_AUTO_ADVERTISEMENT 控制,預設 true)。Auth Key 記得綁 tag——Service 主機必須是標籤身分。

同一個 Service 在多台機器上跑相同的容器,就直接得到高可用:滾動更新時逐台 tailscale serve drain,位址不變、使用者無感。

存取控制 (ACL)

預設的 Policy File 是全部開放——tailnet 內任何裝置都連得到任何裝置。只有自己用還行,多人或多用途的環境該收緊。

一個實際的例子:

{
  "tagOwners": {
    "tag:server": ["autogroup:admin"],
    "tag:container": ["autogroup:admin"]
  },
  "grants": [
    {
      "src": ["autogroup:admin"],
      "dst": ["*"],
      "ip": ["*:*"]
    },
    {
      "src": ["group:family"],
      "dst": ["tag:server"],
      "ip": ["tcp:8096"]
    }
  ],
  "groups": {
    "group:family": ["alice@example.com", "bob@example.com"]
  }
}

這份規則的意思是:管理員能連所有東西,家人只能連到帶 tag:server 標籤的機器的 8096 埠(Jellyfin),其他一律拒絕。

節點加標籤:

sudo tailscale up --advertise-tags=tag:server

加了標籤的節點所有權會轉移給標籤,不再屬於原本的使用者,也不會受該使用者的權限影響。伺服器類的節點建議都打標籤,這樣 ACL 才寫得乾淨,而且成員離職時不會連帶影響伺服器。

另外注意:加標籤需要重新認證,tailscale set --advertise-tags 不能用,要用 tailscale up

常見問題

連線一直走 relay 不是 direct

tailscale netcheck 看自己的 NAT 型態。兩邊都是對稱式 NAT (symmetric NAT) 的話打洞會失敗,只能走中繼。改善方式:

  • 路由器關掉 UPnP 以外的嚴格 NAT 設定,或改用 Full Cone NAT
  • 在其中一邊設定固定的 WireGuard 通訊埠並做通訊埠轉發:tailscaled --port=41641
  • 有一台有公開 IP 的機器就讓它當節點,變成事實上的直連對象

忘記開 IP 轉送

子網路由與出口節點最常見的問題。tailscale status 看起來一切正常、節點也 ping 得到,但流量就是過不去。檢查:

sysctl net.ipv4.ip_forward   # 要是 1

DNS 突然壞掉

MagicDNS 跟本機 DNS 服務衝突。先 sudo tailscale set --accept-dns=false 確認是不是這個原因。

後台一堆離線的殭屍節點

容器沒掛 state volume,或是 Auth Key 沒設 Ephemeral。後台手動刪掉,然後修設定。

結語

Tailscale 最大的價值是把「安全連回內網」這件事的設定成本壓到幾乎為零。不用開通訊埠、不用管憑證、不用處理浮動 IP,裝完登入就有一個私有網路。

實務上我的配置大致是:

  • 家裡一台常開的 Linux 機器做子網路由 + 出口節點,涵蓋整個 192.168.1.0/24
  • 那台同時是 Global nameserver,跑 AdGuard Home,所有節點連上就自動過濾廣告
  • 需要單獨曝露的容器化服務用 Sidecar 模式 + serve.json,完全不開對外通訊埠
  • 會搬遷或要做高可用的服務改用 Tailscale Services,位址跟裝置脫鉤
  • 伺服器節點全部打 tag:server,ACL 只放行必要的通訊埠
  • 完全不用 Funnel,除非真的需要對外公開

不確定要不要開某項功能的時候,原則跟其他網路設定一樣:先關著,等真的需要再開

參考資料

© 2010 - 2026 丁丁 @ThanatosDi
Powered by theme astro-koharu · Inspired by Shoka