Tailscale 取代連接埠轉送:免開路由器連接埠
不用開啟路由器連接埠,也能從外部存取家用 NAS、Raspberry Pi 或 Minecraft 伺服器。了解 Tailscale 如何穿透 NAT、何時改用 relay,以及無法處理的情況。
Tailscale 需要連接埠轉送嗎?
Tailscale 不需要連接埠轉送;若要連線到自己的機器,Tailscale 可完全取代連接埠轉送。tailnet 中的每台裝置(Tailscale 在裝置之間建立的私有網路)都會自行建立對外連線。家用路由器不需要變更任何設定:不需要轉送連接埠、不需要 DMZ(非軍事區)主機、不需要動態 DNS 記錄,也不需要公開 IP。位於 ipTIME 或 Fritz!Box 路由器後方的 NAS(網路附加儲存裝置)、Raspberry Pi 或遊戲伺服器,都能讓您從任何地方透過筆電,以其私有位址存取;路由器的對外連入端仍維持關閉。
它不會處理的情況也很簡單。Tailscale 只能連線到已登入您的 tailnet,或已分享至其中的裝置。網際網路上的陌生人,或尚未加入的朋友,無法透過 Tailscale 存取任何內容。將服務暴露給整個公開網際網路是另一項工作,本文接近結尾處會加以說明。
Tailscale 如何在未設定連接埠轉送的情況下穿透 NAT
之所以需要連接埠轉送,是因為存在 NAT(網路位址轉換)。路由器擁有唯一的公開 IPv4 位址,而後方每台裝置都使用私有位址。抵達路由器的入站封包沒有資訊可指出應交給哪台私有裝置,因此路由器會丟棄它。連接埠轉送是手動建立的規則,表示「連接埠 25565 屬於 192.168.0.20」。Tailscale 會透過以下四個步驟達到相同結果,而不需要這項規則。
第一,每個節點都會主動對外連線。啟動時,tailscaled 會透過 TCP 443 開啟至協調伺服器的 HTTPS 連線。它會傳送自己的 WireGuard 公開金鑰,並取得 tailnet 中其他節點的公開金鑰與位址。協調伺服器不會承載你的網路流量,只負責傳遞金鑰與位址簿。
第二,每個節點會得知自己從外部看起來的樣子。它會透過 UDP,向 Tailscale 的 relay server 在連接埠 3478 發送 STUN(session traversal utilities for NAT)要求。回應會包含路由器為該出站封包配置的公開 IP 與連接埠。這就是連接埠轉送原本會手動建立的對映,只是這次由路由器針對出站流量自行建立。如果路由器支援 UPnP 或 NAT-PMP,Tailscale 也會自動要求路由器建立對映。這能提高成功率,但並非必要條件。
第三,兩端會進行打洞。節點 A 與節點 B 會透過協調伺服器取得彼此的公開端點。兩者會同時從自己的監聽器發送 UDP 封包,預設使用連接埠 41641,前往對方的公開端點。每台路由器都已為自己的節點保留出站對映,因此從另一端抵達的封包會符合該對映並獲准進入。從此開始,兩個節點會透過 WireGuard 直接通訊,而路由器仍未設定任何規則。
第四,打洞失敗時,流量會經由 relay server 傳送。CGNAT(carrier-grade NAT,ISP 將你置於其控制的第二層 NAT 後方)與 symmetric NAT(路由器會針對每個目的地選用新的連接埠,因此 STUN 回應失去作用)都會使第三步失敗;封鎖 UDP 的企業防火牆也會造成相同結果。接著,Tailscale 會透過 TCP 443,將加密的 WireGuard 封包傳送至 DERP(designated encrypted relay for packets)伺服器。relay server 只能看到密文。這也會增加延遲並降低吞吐量;為什麼經由 relay server 的 Tailscale 連線速度較慢,以及如何改為直接連線說明如何判斷目前使用的路徑,以及需要修改哪些設定。
以上四個步驟都不是對路由器建立入站連線。這就是不需要連接埠轉送的完整原因。
安裝用戶端並檢查路徑
每台裝置只需執行一個指令稿,並完成一次登入。
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale ip -4tailscale up 會輸出登入 URL。開啟該 URL、登入後,裝置就會加入 tailnet。tailscale ip -4 會輸出裝置在 100.64.0.0/10 範圍內的 tailnet 位址。該位址在重新開機及切換網路後都會保持不變,因此應將它填入 SSH 設定與遊戲用戶端。
從 tailnet 中的另一台裝置檢查前一台裝置的路徑:
tailscale ping nas使用主機名稱或 tailnet 位址。第一次回應通常會顯示 via DERP,因為直接路徑仍在協商中。幾秒內,回應應切換為公開 IP 與連接埠,表示穿透 NAT 成功。若一分鐘後回應仍顯示 via DERP,表示其中一端位於無法穿透的 NAT 後方,目前使用的是轉送連線。
值得新增的單一防火牆規則
Tailscale 在大多數網路上不需修改防火牆,因為通常允許對外 UDP 流量。新增一項選用規則可提高建立直接連線的機率:允許 UDP 41641 通過。
在家用路由器或工作場所的防火牆上,這表示允許對外傳送至連接埠 41641 的 UDP 流量。如果對外 UDP 流量受到限制,也要允許對外傳送至連接埠 3478 的 UDP 流量,供 STUN 使用。大多數家用路由器原本就已允許,因此不需進行任何設定。
在 VPS 上,有用的方向是對內。VPS 具備公開 IP,前方沒有 NAT,因此新增 UDP 41641 的對內規則後,VPS 對所有對等點而言都更容易連線:即使對等點自身的 NAT 較難穿透,其連線穿透封包仍會抵達 VPS。使用 ufw:
sudo ufw allow 41641/udp
sudo ufw statusufw status 應列出 41641/udp 為來自 Anywhere 的 ALLOW。如果供應商在控制面板中另設網路防火牆,也需要在該處新增相同規則,因為封鎖在供應商網路邊界的封包永遠不會抵達 ufw。此規則是便利性設定,不是必要條件。即使關閉該連接埠,VPS 仍會加入 tailnet,對等點仍可連線到它;其中部分連線會透過 relay,而非直接連線。
從外部連線到家中的 NAS 或 Raspberry Pi
第一種情況最簡單,也是多數人所說的「使用 Tailscale 進行連接埠轉送」:從不在家中的筆電或手機,連線到家中的設備。
在家中的設備和筆電上安裝用戶端即可。這就是全部設定。現在,NAS 或 Pi 執行的每項服務,都能透過其 tailnet 位址回應,完全不需要轉送連接埠:
ssh pi@100.101.102.103
curl -I http://100.101.102.103:8080/將位址替換為家中設備執行 tailscale ip -4 後顯示的結果。SSH 登入行為應與連線至家中 Wi-Fi 時完全相同,而 curl -I 應顯示該設備所執行 Web 應用程式的 HTTP 狀態列。由於連線是以登入裝置所繫結的 WireGuard 金鑰進行驗證,因此原本不適合透過轉送連接埠公開的服務,例如 SMB(server message block)共用或 Web 管理面板,在這裡可以安全使用:只有你自己的裝置能夠向它傳送封包。中間的 ipTIME 或 Fritz!Box 不會看到任何入站連線,也不需要修改設定。即使 ISP 將你置於 CGNAT 後方,這種方式仍可運作,因為家中設備只會發起對外連線;最差的情況下,路徑會經過中繼。
新建立的 tailnet 預設會啟用 MagicDNS,為每個節點提供名稱。因此,筆電連上 tailnet 後,ssh pi@nas 也能正常運作。
裝置無法執行 Tailscale 時:子網路路由器
有些裝置無法執行用戶端,例如印表機、IP 攝影機、作業系統受限的舊型 NAS,或智慧型電視。子網路路由器可以解決這個問題。家用網路中只要有一台能執行 Tailscale 的機器即可,Pi 就足夠。這台機器會公布整個家用子網路,其他 tailnet 裝置則透過它路由到該子網路。
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-tailscale.conf
sudo sysctl --system
sudo tailscale up --advertise-routes=192.168.0.0/24請使用實際的家用子網路。接著,必須在管理主控台的該機器路由設定中核准此路由;Linux 用戶端則必須使用 sudo tailscale set --accept-routes 選擇啟用。完成後,從筆記型電腦執行 ping 192.168.0.50 即可連線到家中的攝影機。轉送 sysctl 設定十分重要,因為未設定時,Pi 會丟棄所有目的地不是自己的封包。此時路由雖然顯示為已核准,但路由後方的裝置仍無法回應。核准步驟、用戶端端的選擇啟用方式,以及其他造成路由顯示已核准但無法連線的原因,請參閱執行 Tailscale 子網路路由器。該文件使用 VPS 作為路由器,但同樣適用於客廳中的 Pi。
讓朋友加入 Minecraft 伺服器,無須開放路由器連接埠
第二種情境是在家中電腦上執行 Minecraft 伺服器,讓朋友加入。傳統做法是在路由器上轉送 TCP 25565,並提供你的公開 IP 位址;但這也會讓網際網路上的所有掃描器取得該位址。Tailscale 則以分享功能取代這種做法。
共有兩種方式。第一種是邀請朋友以使用者身分加入你的 tailnet。這種方式可行,但 免費方案的使用者席次有限,而且會讓他們取得整個網路的登入權限,這超出遊戲所需。第二種也是較佳的方式,是分享節點。在管理主控台中開啟 Machines 頁面,找到遊戲電腦,開啟其選單並選擇 Share。Tailscale 會建立邀請連結。每位朋友都需要擁有自己的免費 Tailscale 帳戶。這會讓該帳戶成為其個人小型 tailnet 的擁有者。接著,朋友使用該帳戶接受連結。分享的電腦會出現在對方的機器清單中,而且只會顯示該電腦。分享會讓接收者只能存取分享的電腦,無法存取你的其他 tailnet 資源。分享的電腦預設會隔離:它可以接收來自朋友 tailnet 的連線,但無法主動建立任何連線。
朋友在 Minecraft 中使用其 tailnet 位址 100.101.102.103:25565 新增伺服器;如果連接埠使用預設值,也可以只輸入該位址。遊戲電腦完全不需要轉送連接埠,路由器也不必修改設定。分享的電腦不會公告子網路路由,因此這種方式適用於直接在分享電腦上執行的服務,正好符合遊戲伺服器的情境。
限制是每位玩家都必須執行 Tailscale 並接受分享。對一群朋友而言,這並不是問題。但如果是任何人都能加入的公開伺服器,這種方式就不適用;接下來兩節會說明解決方法。
在 VPS 上執行遊戲伺服器,並將 RCON 限定在 tailnet
略過連接埠轉送的另一種方式,是不要在家中託管遊戲。VPS 具有公開 IP,且不受 NAT 影響,因此無須經過任何路由器,遊戲連接埠即可對外開放。在 VPS 上執行 Minecraft 伺服器說明規模配置、Java flags、備份與 systemd unit。這裡的重點是哪些連接埠會暴露在網際網路上。
Minecraft 伺服器會開啟兩個連接埠。TCP 25565 是遊戲連接埠,玩家需要使用它。TCP 25575 是 RCON(remote console),接受密碼後即可執行任何伺服器命令,包括 op 與 stop。對網際網路開放的 RCON 連接埠會成為密碼猜測攻擊的目標。將 VPS 加入 tailnet,並為這兩個連接埠設定不同規則:
sudo ufw allow OpenSSH
sudo ufw allow 25565/tcp
sudo ufw allow in on tailscale0 to any port 25575 proto tcp
sudo ufw enable
sudo ufw status第二條規則會將遊戲連接埠開放給所有人。第三條規則只允許從 tailscale0 介面進入的封包使用 RCON,這表示只有 tailnet 中的裝置可以連線。公開 IP 仍會回應 25565,而從公開網路連線到 25575 的請求,會被 ufw 的預設拒絕政策丟棄。請從位於 tailnet 中的筆記型電腦測試兩者:
nc -zv 100.101.102.103 25575
nc -zv <vps-public-ip> 25575第一個命令應輸出 succeeded。第二個命令應暫停,之後逾時,因為封包是從公開介面進入,且沒有符合任何允許規則。同樣的模式也適用於 SSH、網頁地圖、資料庫或 metrics dashboard:在公開 IP 上開放公開連接埠,僅在 tailscale0 上開放管理連接埠。
向整個網際網路公開服務:Funnel 或 VPS 反向通道
第三種情況是 Tailscale 本身無法解決的問題。部落格、公開 API、公開遊戲伺服器或狀態頁面,其訪客不在你的 tailnet 中,也不會加入其中。這裡有兩種工具可處理,而且各自都有獨立文章。
Tailscale Funnel 會透過 Tailscale 的中繼站,將節點上的 HTTPS 服務公開至網際網路。它只能使用 TLS(傳輸層安全性),且僅支援 443、8443 和 10000 埠。因此適合 Web 應用程式,不適合使用 25565 埠的原始遊戲協定。Tailscale Serve 與 Funnel 的差異說明兩者各自會公開什麼,以及公開給哪些人。
VPS 反向通道可處理其他情況。家中的主機會對具有公開 IP 的 VPS 建立輸出通道,VPS 再透過該通道,將任意連接埠號碼上的公開 TCP 或 UDP 連接埠轉送回家中。若要在 CGNAT 後方的家用網路託管公開 Minecraft 伺服器,這就是適用的工具;在 CGNAT 後方使用 VPS 反向通道架設家用伺服器會逐步說明設定方式。請從這兩種工具中擇一,不要再尋找能將連接埠開放給全世界的 Tailscale 設定。這樣的設定不存在。
Tailscale 不會做什麼
- 它不會為任意公網用戶端轉送連接埠。來自 tailnet 外部的封包不會抵達您的節點,因為其中沒有對應的 WireGuard 金鑰;沒有有效金鑰的 WireGuard 封包會直接丟棄,不會回應。
- 它不會提供讓公眾連入的方式。使用者必須是您 tailnet 的成員,或已接受共用的節點。
- 它不保證使用直接路徑。在複雜的 NAT 環境中,連線會經由中繼轉送,因此速度較慢。
- 它不會開啟路由器的連入通道。路由器仍維持關閉,這正是其設計目的。
FAQ
Tailscale 需要連接埠轉送嗎?
不需要。每個 Tailscale 節點只建立對外連線。它會透過 HTTPS over TCP 443 連線至協調伺服器,並使用 STUN over UDP 3478 取得公開位址。直接的對等連線會在連接埠 41641 上透過 UDP hole punching 建立;若 hole punching 失敗,流量會透過 TCP 443 經由 DERP relay 傳送,同樣屬於對外連線。家用路由器不需要設定連接埠轉送或 DMZ host;位於 CGNAT 後方的裝置也能以相同方式加入。
Tailscale 能取代 Minecraft 伺服器的連接埠轉送嗎?
可以,適用於讓朋友加入的伺服器。在遊戲電腦上安裝 Tailscale,從管理主控台的 Machines 頁面將該電腦分享給每位朋友。朋友即可連線到該電腦在 tailnet 上的位址與連接埠 25565,不需要轉送連接埠。它無法取代公開伺服器的連接埠轉送,因為 tailnet 外部的玩家無法連線到該節點。若要提供公開伺服器,請將遊戲託管在具備公開 IP 的 VPS 上,並讓 RCON 留在 tailnet 內;或者從家用主機建立 VPS reverse tunnel。
Tailscale 使用哪些連接埠?
3 個。對外 TCP 443 用於連線協調伺服器及傳送 DERP relay 流量。對外 UDP 3478 用於 STUN,以探索公開位址。UDP 41641 是直接連線使用的預設 WireGuard listener;若 41641 已被占用,可以變更此連接埠。這些連接埠都不需要開放入站連線。在 VPS 上允許入站 UDP 41641 是選擇性的,通常能讓對等節點更常建立直接連線。
為什麼我的 Tailscale 連線使用 relay,而不是直接連線?
tailscale ping 會在 UDP hole punching 無法完成時持續回應 via DERP。常見原因包括 hole punching 無法穿透的 NAT,例如 CGNAT,或針對每個目的地都指派新連接埠的 symmetric NAT;另一個原因是防火牆封鎖對外 UDP。請修正你能控制的部分:允許對外 UDP 41641 和 3478,或讓其中一個對等節點位於已開放入站 UDP 41641 的 VPS 上,使另一端的 hole punching 始終有固定目標。