SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-30

如何在 VPS 上執行 Tailscale subnet router

從 VPS 將私有網路廣告至 tailnet,涵蓋路由核准、重開機後仍持續的 IP forwarding,以及 Linux 必須使用的 --accept-routes 旗標。

Tailscale subnet router 的功能

Tailscale subnet router 是一台向 tailnet 宣告整段私有 IP 位址的機器,因此 tailnet 上的每部裝置都能連線到該範圍內的位址,即使其中沒有任何裝置執行 Tailscale。

tailnet 是你的私有 Tailscale 網路,也就是登入同一個帳戶或組織的所有裝置。

人們最常將它與 exit node 混淆,但 exit node 的作用相反。

exit node 會將裝置的所有網路流量經由 VPS 對外傳送,因此 VPS 會成為該裝置連線至公用網際網路的路由。

每個概念用一句話說明。

subnet router 會讓 tailnet 能夠連線到一個私有網路。

exit node 會變更公用流量離開網路的位置。

如果你需要的是第二種功能,請改閱如何在 VPS 上執行 Tailscale exit node。

這兩者使用不同的旗標。

同一台 VPS 可以同時提供這兩種功能,但它們解決的是不同問題,失效原因也不同。

VPS 需要子網路由器的情況

常見情況是供應商已經提供私有網路。VPS 具有公開位址,並透過第二個介面連線到私有網段;該網段上的其他伺服器完全沒有公開位址,例如位於 10.0.0.20 的資料庫,以及位於 10.0.0.30 的備份目標。只要在一台 VPS 上安裝 Tailscale 並廣告 10.0.0.0/24,筆電就能直接連線到這些私有位址。網段上的其他設定不必變更,資料庫也不會取得公開位址。如果你只需要從該網段存取單一連接埠上的單一 Web 應用程式,廣告整個範圍就超出實際需求;此時 Tailscale serve 會改為在該單一連接埠上提供 HTTPS。同樣的原則也適用於刻意只繫結至 localhost 的 daemon,例如 在 systemd 下以無頭模式執行的 dsh。此時,VPS 上的 tailnet 位址可以取代原本為了存取其 UI 而必須保持開啟的 SSH tunnel。

另一種情況是 VPS 另一端的網路。這可能是由自己的路由器連線到網路的家用或辦公室 LAN(區域網路),也可能是一組完全無法執行 Tailscale 的設備,例如受管理的交換器或韌體鎖定的舊 NAS。該網路上的一台 Linux 主機會成為其他所有設備的子網路由器。在家中,這台主機通常是執行於既有 hypervisor 上的小型 VM;在決定服務應該位於 tunnel 的哪一端之前,應先釐清 家中 Proxmox 主機與租用 VPS 的成本比較。

這兩種情況都有相同的要求。子網路由器必須先能透過自己的 routing table 和 firewall 連線至它所廣告的範圍。Tailscale 不會建立這條連線。它只會將流量傳送至路由器,再交給 kernel 進行轉送。

先安裝 Tailscale,並先檢查本機路由

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

此指令碼會偵測發行版、加入 Tailscale 的套件儲存庫、安裝 tailscale 指令與 tailscaled daemon,然後啟用服務。使用 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 會立即生效,但下次開機時就會消失。因此,子網路由器可能運作數週,卻在 kernel upgrade 後重新開機的隔天早上停止轉送。令人困惑的是,表面上沒有任何異常。tailscale status 仍顯示節點在線上,管理主控台仍顯示路由已核准,client 也仍保留已安裝的路由。封包抵達 VPS 後,kernel 會直接丟棄它們,且不會寫入任何日誌。將這些值寫入 /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

在已登入您 tailnet 的 VPS 上,直接修改現有設定:

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,指令會遭拒,因為前綴後的位元不是 0;錯誤訊息會指出您可能想使用的前綴。若要停止宣告路由,請使用 sudo tailscale set --advertise-routes= 設定空清單。

在管理主控台核准路由

公告路由是提出請求,不會立即變更設定。在管理員核准前,沒有用戶端會收到該路由,該範圍內也沒有任何項目可連線。這是刻意的設計,因為如果任何機器都能將自己加入所有人的路由表,就能攔截任意範圍的流量。

請在管理主控台的 Machines 頁面核准路由。VPS 會以子網路標籤列出。開啟該列,找到子網路區段,編輯路由設定,勾選該路由後儲存。

核准是以 prefix 為單位。今天公告 10.0.0.0/24,下個月再公告 192.168.50.0/24 時,新 prefix 會以未核准狀態加入,而舊 prefix 仍可正常運作。對 VPS 而言,已核准的路由與遭忽略的路由看起來完全相同,因此在進行其他疑難排解前,請先檢查主控台。

您可以在 tailnet policy 檔案中加入 autoApprovers 區塊,以略過手動步驟:

{
  "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,路由在公告時就會立即獲得核准。該標籤必須先存在於同一個 policy 檔案的 tagOwners 區段中。如果您透過 script 重建 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

Linux 上的 Tailscale 不會將已接受的路由放入主要路由表,而是放入路由表 52,並安裝 policy rules。使用 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 透過您的私有 nameserver 解析為 10.0.5.20,而您公布了 10.0.0.0/24。查詢會成功,因為 DNS(domain name system)解析與 IP routing 是分開的步驟,兩者都不會互相檢查。接著,前往 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 或另外明確指定的 prefix,然後在主控台核准新的 prefix。

nameserver 本身也有一個相應的陷阱。如果您在管理主控台中將全域 nameserver 設為私有位址,例如 10.0.0.53,該位址必須位於已核准的路由內,否則裝置完全無法連線到 resolver。在指向無法連線的 resolver 時啟用覆寫本機 DNS server 的選項,會使 tailnet 中的每台裝置同時失去名稱解析能力,包括前一秒仍能正常運作的裝置。請先公布並核准通往 resolver 的路由,再變更 DNS 設定。如果您持續遇到 tunnel 內的 DNS 問題,WireGuard tunnel 中 DNS 發生故障的方式 說明了相同的機制,但不涉及上層的協調層。

來源 NAT 與站點對站點連線

依預設,子網路路由器會將每個轉送封包的來源位址改寫為自己的私有位址。這就是 SNAT(來源網路位址轉譯)。這樣做可讓回應正常運作,而不必修改私有網路上的任何設定:10.0.0.20 的資料庫會回應 VPS,因為它原本就知道如何連線到 VPS。代價是,資料庫會將所有 tailnet 連線視為來自 VPS,因此依來源套用的防火牆規則與存取日誌都無法提供實用資訊。

如果要保留用戶端實際的 tailnet 位址,請在 Linux 上關閉此功能:

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

接著,私有網路上的主機需要建立返回 100.64.0.0/10 的路由。100.64.0.0/10 是 Tailscale 指派給裝置的位址範圍,該路由應指向子網路路由器。若沒有這條返回路由,回應會送往預設閘道,無法抵達來源,因此連線會在第一個封包後停滯。請在私有網路的閘道上新增靜態路由,或維持 SNAT 啟用。

站點對站點連線是由兩台子網路路由器同時執行上述設定。每台路由器各自宣告自己的網路,並接受另一台路由器宣告的網路:

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

在另一台路由器上使用其自身位址範圍執行對應命令。兩個位址範圍必須不同。如果大型傳輸停滯,但 ssh 與 ping 正常,原因通常是 MSS(最大區段大小)。MSS 是 TCP 封包可承載的最大資料量。通道額外負載會使轉送封包超過中間某條連線可承載的大小,因此需要限制 MSS:

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 儲存這項規則,否則下次開機時規則會消失。

維持運作的例行維護

截至 August 2026,節點金鑰預設會在 180 days 後到期。子網路路由器上的金鑰到期時,節點會登出,整個公告的網段也會變得無法連線,而且沒有任何設定變更可以解釋這個現象。請在管理主控台的 Machines 頁面,停用這台機器的金鑰到期功能,並記錄你已完成這項設定。

Tailscale 會優先在對等節點之間建立直接連線;如果無法建立,則會改用其中繼伺服器。中繼伺服器可以正常運作,但會增加延遲。具備公開位址的 VPS 是最簡單的情況:允許輸入 UDP 41641 後,大多數對等節點都能直接連線。如果由 ufw 管理防火牆,VPS 實際需要的 ufw 規則說明了語法。

存取規則是另一個必要部分。在預設的 tailnet 中,你的每台裝置都能連線到其他裝置,因此核准的路由會直接生效。建立 ACL 政策後,規則的目的端必須指定私有網段,因為 10.0.0.20 不是 tailnet 位址,也不會受到以 tailnet IP 或標籤撰寫的規則涵蓋。

最後,請決定是否接受使用不由你管理的協調伺服器。Tailscale 的控制平面是代管服務。你的金鑰會留在自己的機器上,但帳戶與政策檔案會存放在該服務中。在將通往私有網路的路由交給它之前,應先評估控制平面遭入侵或身分登入資訊遭竊時,攻擊者實際能執行哪些操作;Tailscale 的信任模型說明了這個邊界的位置。費用通常不是使用者離開它的主要原因,因為免費方案涵蓋最多 6 位使用者,且每位使用者的裝置數量不限。不過,以標籤啟動的子網路路由器,計算方式與以你的身分登入的路由器不同。超過這個範圍後,費用是按照人數而非機器數量計算,因此在新增會使你超出限制的帳戶前,值得先確認家庭或 5 人團隊在免費方案用完後實際需要支付的費用。執行自架 Headscale,也就是自行託管的 Tailscale 控制伺服器,可以將控制平面留在自己的 VPS 上,但必須自行維護。對相同疑慮的另一種做法,是連 Tailscale 用戶端也一併捨棄;自架 NetBird VPN 伺服器會將協調層及其 mesh 用戶端放在一台由你控制的機器上。如果你仍在這種模式與手動撰寫設定檔之間猶豫,WireGuard 與 Tailscale 的比較會說明協調層能提供什麼,以及需要付出哪些代價。

FAQ

子網路由器與 exit node 有何不同?

子網路由器會公告一段私有位址範圍,讓 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 轉送。使用 sysctl -w 設定的值不會在重新開機後保留,因此請將它寫入 /etc/sysctl.d/99-tailscale.conf,再使用 sysctl net.ipv4.ip_forward 確認。如果已啟用轉送,但該範圍仍無法連線,請在管理主控台檢查該節點。節點金鑰預設會在 180 天後到期。子網路由器的金鑰到期時,看起來像是網路故障,而不是帳戶問題。

兩個子網路由器可以公告相同的範圍嗎?

不能公告完全相同的範圍。前綴長度不同的重疊範圍可以共存,而且會優先使用最具體的路由。實作故障切換時需要特別注意:持有較具體前綴的路由器離線後,Tailscale 不會改用較寬的路由,因此該網路流量會停止。若要建立真正的備援組,請讓兩台路由器都公告相同的具體前綴。

主機名稱可以解析,但連線逾時。為什麼?

DNS 解析與路由是不同步驟。名稱可能解析為沒有任何已核准路由涵蓋的位址,封包接著會經由用戶端的預設閘道送出。請在用戶端執行 ip route get <address>。如果結果不包含 dev tailscale0,請公告涵蓋該位址的範圍,並在管理主控台核准新的前綴。