我已經在執行 Tailscale — 其中一個 LXC 設定為子網路路由器,將其他容器暴露在 tailnet 上。因此我可以遠端存取它們。我只是還是要記住那些 IP。

我想要 https://proxmox.home.lab:8006。我想要輸入名稱,而不是數字。

Tailscale App Connectors 成為了解決方案。設定過程花費的時間比預期還長,所以以下是實際可行的做法。


最終成果

一個 LXC 執行三項工作:子網路路由器、應用程式連接器,以及 DNS 伺服器。tailnet 上的任何裝置都會將 <service>.home.lab 解析至正確的容器 IP,並自動路由流量。App Connectors 適用於 所有 Tailscale 方案 — 請查看定價頁面確認,因為方案可能變動。

本指南假設您已經有一個 Tailscale LXC 作為子網路路由器。如果沒有,這個影片 會引導您完成設定 — 然後回到步驟 2,在此基礎上新增應用程式連接器角色。

有三個值貫穿整個設定過程。 如果其中任何一個在步驟之間出現差異,某些功能會無聲無息地失效:

必須一致的位置
標籤名稱(例如 tag:app-connector ACL tagOwners、ACL nodeAttrs、ACL autoApprovers、tailscale up 指令
網域名稱後綴(例如 home.lab ACL domains 清單、dnsmasq 項目、Tailscale Apps 頁面、分割 DNS 限制
區域網路子網路(例如 192.168.1.0/24 ACL autoApprovers、tailscale up 指令、dnsmasq IPs

步驟 1:更新 Tailscale ACL 政策

前往 Tailscale 管理主控台存取控制。您會看到一個 huJSON 編輯器,顯示您目前的政策。請勿取代它 — 將這些區段以最上層金鑰的形式合併進去。如果您已經有 grants 區塊,請在其中新增新規則,而非建立第二個區塊。

{
  "tagOwners": {
    "tag:app-connector": []
  },

  "grants": [
    { "src": ["*"], "dst": ["*"], "ip": ["*"] }
  ],

  "autoApprovers": {
    "routes": {
      "0.0.0.0/0": ["tag:app-connector"],
      "::/0":      ["tag:app-connector"]
    }
  },

  "nodeAttrs": [
    {
      "target": ["*"],
      "app": {
        "tailscale.com/app-connectors": [
          {
            "name": "[CHOOSE_NAME_FOR_THE_APP_CONNECTOR]",
            "connectors": ["tag:app-connector"],
            "domains": [
              // 您需要公開的任何網域
              "proxmox.home.lab",
              "homeassistant.home.lab"
            ]
          }
        ]
      }
    }
  ]
}

進入全螢幕模式 離開全螢幕模式

陷阱: nodeAttrs 中的 target 必須為 ["*"]。我一開始嘗試 ["tag:app-connector"],但無法運作。Tailscale 會丟出:tailscale.com/app-connectors: can only be specified with target "*"。應用程式定義中的 connectors 欄位是用來控制哪個節點執行工作。target 控制哪些節點接收此設定,而應用程式連接器必須設定為所有人。


步驟 2:將 LXC 設定為應用程式連接器

在安裝 dnsmasq 之前,請檢查 systemd-resolved 是否佔用連接埠 53 — 如果是,dnsmasq 將無法啟動:

systemctl is-active systemd-resolved

進入全螢幕模式 離開全螢幕模式

如果正在執行,請停用其 stub 監聽器:

sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
systemctl restart systemd-resolved

進入全螢幕模式 離開全螢幕模式

現在 SSH 進入您的 Tailscale LXC,並宣告其新角色:

tailscale up \
  --advertise-connector \
  --advertise-tags=tag:app-connector \
  --advertise-routes=192.168.1.0/24

進入全螢幕模式 離開全螢幕模式

請將 192.168.1.0/24 替換為您實際的區域網路子網路。

陷阱: 節點必須明確使用 --advertise-connector 選擇加入。我花了一些時間在管理主控台尋找指定節點為連接器的按鈕 — 並不存在。節點透過 CLI 宣告自己的角色。在您執行此指令之前,Apps UI 中不會出現任何可選的項目。

驗證是否成功: 前往管理主控台 → 機器。您的 LXC 現在應該會在旁邊顯示應用程式連接器徽章。


步驟 3:安裝並設定 dnsmasq

應用程式連接器負責路由 — 但它們不會將網域名稱解析為 IP。您需要本機 DNS 伺服器來執行此操作。在同一個 LXC 上使用 dnsmasq 是最簡單的選擇。

apt update && apt install -y dnsmasq

進入全螢幕模式 離開全螢幕模式

編輯 /etc/dnsmasq.conf 並附加:

# 如果沒有這行,dnsmasq 會拒絕來自 Tailscale 介面的查詢。
# systemd 單元會傳遞 --local-service,這會限制在區域子網路;
# 新增 interface=tailscale0 會覆寫此行為。
interface=tailscale0
bind-interfaces

# 每個容器一行 — 使用您實際的區域網路 IP
address=/proxmox.home.lab/192.168.1.2
address=/homeassistant.home.lab/192.168.1.3

進入全螢幕模式 離開全螢幕模式

已經在使用 dnsmasq 進行 DHCP 或其他用途? 只需將 interface=tailscale0 這一行與您現有的 interface= 行一起新增,而非取代它們。

啟動並驗證:

systemctl enable --now dnsmasq
systemctl status dnsmasq   # 應為 active,不顯示「limited to local subnets」

dig @127.0.0.1 proxmox.home.lab
# ANSWER SECTION 應顯示您容器的 IP

進入全螢幕模式 離開全螢幕模式

陷阱: 首次啟動後,狀態可能顯示 DNS service limited to local subnets。這來自 systemd 單元檔案中內建的 --local-service — 沒有設定檔選項可以覆寫它。解決方法是 interface=tailscale0,這會告訴 dnsmasq 接受 Tailscale 介面上的查詢。重新啟動後,警告就會消失。


步驟 4:在管理主控台註冊應用程式

管理主控台 → 應用程式新增應用程式

  • 名稱:任何描述性名稱
  • 類型:自訂
  • 網域:您的 home.lab 網域,以逗號分隔(與步驟 1 相同)
  • 連接器標籤:tag:app-connector
  • 儲存

您會注意到網域同時出現在 ACL nodeAttrs 和這裡。它們的目的不同:ACL 控制路由政策(哪個節點處理哪個流量),而 Apps UI 則註冊 Tailscale 用於 DNS-over-HTTPS 轉送的連接器關聯。兩者都需要相同的網域。


步驟 5:新增分割 DNS 名稱伺服器

管理主控台 → DNS新增名稱伺服器

  • 名稱伺服器:您的 LXC 的 tailnet IPv4 位址 — 100.x.y.z 那個(在 LXC 上執行 tailscale ip -4
  • 勾選 限制至網域
  • 網域:home.lab
  • 儲存

同時確保同一頁面上的 Magic DNS 已啟用。沒有它,分割 DNS 無法運作。

這會告訴 Tailscale:對於 home.lab 下的任何項目,都詢問這個特定的名稱伺服器。其他一切都使用一般 DNS。


步驟 6:設定用戶端

Linux:

tailscale set --accept-routes=true --accept-dns=true

進入全螢幕模式 離開全螢幕模式

使用 GUI 應用程式的 macOS:
Tailscale 選單列 → 偏好設定 → 啟用 使用 Tailscale DNS。完成。

僅使用 macOS CLI(無 GUI 應用程式):

陷阱: macOS 上的 Tailscale CLI 無法管理系統 DNS。tailscale set --accept-dns=true 會靜默接受旗標,但不會執行任何操作 — CLI 沒有機制可以在沒有 GUI 應用程式的情況下安裝所需的 Network Extension。tailscale debug resolve your-domain.home.lab 會傳回 no such host,即使 netmap 顯示路由已正確設定。

因應措施 — 手動將您的 Wi-Fi DNS 指向 LXC:

sudo networksetup -setdnsservers Wi-Fi <LXC tailnet IPv4>

進入全螢幕模式 離開全螢幕模式

還原:

sudo networksetup -setdnsservers Wi-Fi "Empty"

進入全螢幕模式 離開全螢幕模式


存取您的服務

https://proxmox.home.lab:8006
http://homeassistant.home.lab:8123

進入全螢幕模式 離開全螢幕模式

應用程式連接器不會處理連接埠 — 瀏覽器預設使用 80。對於不在 80 或 443 上執行的服務,請包含連接埠。如果您想完全省略連接埠,請在服務前面放置反向代理(Caddy 或 nginx)。


另一個陷阱:Chrome 的 DNS-over-HTTPS

這是跨平台的問題,不僅限於 macOS。Chrome 有自己的 DoH,會完全繞過系統 DNS。如果 dig 能正確解析,但 Chrome 顯示「無法連線至網頁」,原因就在這裡。

停用它:設定 → 隱私權和安全性 → 安全性 → 使用安全 DNS → 關閉。


新增容器

三個地方,都使用完全相同的網域名稱:

  1. dnsmasq 設定 — 新增 address=/newservice.home.lab/<區域網路 IP> 然後執行 systemctl restart dnsmasq
  2. ACL nodeAttrs — 將 "newservice.home.lab" 新增至 domains 清單,儲存
  3. 管理主控台 → 應用程式 — 編輯您的 homelab 應用程式,新增網域

疑難排解

症狀 解決方法
can only be specified with target "*" 將 nodeAttrs 中的 "target": ["tag:app-connector"] 變更為 "target": ["*"]
dnsmasq 顯示「limited to local subnets」 /etc/dnsmasq.conf 中新增 interface=tailscale0 + bind-interfaces,然後重新啟動
dnsmasq 無法啟動 連接埠 53 衝突 — 停用 systemd-resolved stub:sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf && systemctl restart systemd-resolved
dig @<LXC IP> service.home.lab 可運作,但系統 DNS 無法運作 macOS CLI 無法管理分割 DNS — 使用 GUI 應用程式或 sudo networksetup -setdnsservers Wi-Fi <LXC tailnet IPv4>
Chrome:「無法連線至網頁」,儘管 dig 已解析 停用 Chrome 安全 DNS:設定 → 隱私權和安全性 → 安全性 → 使用安全 DNS → 關閉
瀏覽器:「無法連線至網頁」(任何瀏覽器) 缺少連接埠 — 嘗試 https://service.home.lab:<連接埠>
LXC 在管理主控台中未顯示為應用程式連接器 在 LXC 上執行 tailscale up --advertise-connector --advertise-tags=tag:app-connector