整體架構

要解決的問題:家用浮動 IP 經常變動,而中國各地的 DNS 快取更新太慢。因此朋友端常常連不上。解決方法是讓朋友端不再依賴「網域解析」,改用訂閱機制。App 定時自動抓取目前最新的 IP。整個過程不需要人工通知,也不受 DNS 傳播速度影響。

核心是一個 Cloudflare Worker。Worker 依網址路徑判斷是哪個朋友或哪組裝置,再去 KV 讀取目前的 IP。Worker 再依 ?v= 參數決定輸出格式(v2ray、Clash、裸 xray-core config 或一鍵安裝腳本),並即時產生對應的內容回傳。KV 只儲存一個共用值(目前 IP)。所有朋友共用同一個值。每個朋友不同的資料(UUID、shortId、路徑、名稱)直接寫在 Worker 程式碼裡,並由人工維護。

flowchart TD
A["DDNS PowerShell 腳本"] -->|更新 A 記錄| B["Cloudflare DNS"]
A -->|寫入 current_ip| C["Cloudflare KV"]
C --> D["Cloudflare Worker"]
D -->|"依路徑判斷 client"| E["讀取 KV 目前 IP"]
E -->|"?v=v2ray(預設)"| F["base64 vless 連結"]
E -->|"?v=clash"| G["完整 Clash config.yaml"]
E -->|"?v=xrayclient"| H["裸 xray-core config.json"]
E -->|"?v=install"| I["PowerShell 一鍵安裝腳本"]
F --> J["Shadowrocket / v2rayN 訂閱"]
G --> K["Clash / Mihomo 訂閱"]
H --> L["irm 下載後手動跑 xray-core"]
I --> M["irm ... | iex 一鍵安裝/更新"]
          

另外還有一組獨立的 IP_TOKENS 路徑空間,和節點使用的 CLIENTS 完全分開。這組路徑只回傳目前 IP 的純文字,不含任何節點資訊。用途是只需要知道「目前 IP 是多少」的情況。

延伸閱讀:Cloudflare 的 KV 和 Worker 在 AWS、GCP 和 Azure 的對應服務,見雲端服務對照表。

目前的伺服器環境

伺服器端的 Windows 電腦執行 xray + config.json。設定中實際有 4 個 inbound:

Inbound監聽用途
① VLESS Reality Vision(對外)區網 IP:443供所有外部朋友直連。主要入口
② VLESS Reality(本機 Loopback)127.0.0.1:12345用於客戶端設定中的 Loopback 測試。不對外開放
③ VLESS + WebSocket127.0.0.1:8080經過 Cloudflare CDN 中轉的備援線路
④ SOCKS(供 WARP 使用)127.0.0.1:50000流量經由 wgcf-warp outbound 出去的入口

路由規則依 client 的 email 欄位分流。指定給 warp 分組的 user,全部流量經由 Cloudflare WARP 出去。指定給 direct 分組的 user,直接從家裡出去。其他沒有指定的 client,使用 fallback 規則:TCP 經由 warp,UDP 經由 wgcf-warp。email 只是內部路由比對用的識別字。識別字的值和朋友實際看到的訂閱節點名稱不同。兩者可以不一樣。建議保持對應關係,比較容易維護。

完整的 config.json(含 4 個 inbound、routing 規則、wireguard/warp outbound 設定)很長。點下方可以展開,查看佔位結構。實際部署時,對照原始檔案,整段貼回即可。本文不會改變設定的結構。
點擊展開/收起:伺服器端完整 config.json(佔位,稍後貼回)
// ===== 伺服器端完整 config.json(佔位,稍後貼回)=====
// {
//   "log": { "loglevel": "warning" },
//   "inbounds": [
//     // ① VLESS Reality Vision,監聽區網 IP:443,clients 陣列含所有朋友的 uuid/email/flow
//     // ② VLESS Reality,監聽 127.0.0.1:12345,僅供本機 Loopback 測試
//     // ③ VLESS + WebSocket,監聽 127.0.0.1:8080,path 隨機字串,經過 CF CDN 中轉
//     // ④ SOCKS,監聽 127.0.0.1:50000,tag: wgcf-socks-in,供 wgcf-warp outbound 使用
//   ],
//   "dns": { "servers": [ /* 1.1.1.1 / 1.0.0.1 / 8.8.8.8 / 8.8.4.4 DoH */ ] },
//   "routing": {
//     "domainStrategy": "IPIfNonMatch",
//     "rules": [ /* 依 user(email)分流 warp / direct,詳見本節文字說明 */ ]
//   },
//   "outbounds": [
//     // wireguard(tag: wgcf-warp,Cloudflare WARP 端點)
//     // socks(tag: warp,轉給本機 wgcf 代理)
//     // freedom(tag: direct,sendThrough 綁定區網 IP)
//     // blackhole(tag: block)
//   ]
// }
//
// 完整內容見「Cloudflare KV Worker 訂閱自動更新 建置指南 v2.md」,之後直接整段貼回這裡。

建置步驟

1. 建立 Cloudflare KV Namespace(只需做一次)

  1. 在 Dashboard 的「Workers 和 Pages」→「KV」,建立 namespace(例如 vpn-sub)
  2. 記錄 Namespace ID 和 Account ID
  3. API Token 必須有 Workers KV Storage:Edit 權限。可以在 DDNS 腳本現有的 Token 上加入同一個權限。

這一步完成後,KV 就設定好了。之後,腳本只會透過 API 自動更新 KV 的值。不需要再手動修改 KV。

2. 部署 Worker(四種輸出格式)

路徑格式一覽:

路徑寫法功能使用對象
/{token} 或 ?v=v2raybase64 編碼的 vless 連結(多個節點用多行)Shadowrocket / v2rayN
?v=clash完整 Mihomo / Clash config.yamlClash 系列 App
?v=xrayclient裸 xray-core config.json(?i= 可以指定多節點群組中的第幾個)桌機直接執行 xray-core
?v=installPowerShell 一鍵安裝/更新腳本irm ... | iex 直接執行
/{ip_token}(獨立於 CLIENTS)純文字,只回傳目前 IP其他只需要知道目前 IP 的用途

CLIENTS 物件支援兩種寫法。單一 client 直接寫 { uuid, sid, name }。多節點群組(例如同一人需要 direct 和 warp 兩個節點,放在同一份訂閱裡)寫成 { clients: [ {...}, {...} ] }。Worker 內部統一用 client.clients || [client] 轉成陣列處理。

點擊展開/收起:Cloudflare Worker 完整程式碼(佔位,稍後貼回)
// ===== Cloudflare Worker 完整程式碼(佔位,稍後貼回)=====
// 內容包含:
//   - const IP_TOKENS = { "隨機字串": { name } }
//   - const CLIENTS = { "隨機路徑": { uuid, sid, name } | { clients: [...] } }
//   - const SNI / PBK 共用參數
//   - export default { async fetch(request, env) { ... } }
//       依 path 比對 IP_TOKENS → 純文字回傳 IP
//       依 ?v= 參數分流到 buildXrayConfig() / buildInstallScript() / buildClashConfig()
//       預設輸出 base64 編碼的 vless 連結
//   - function buildXrayConfig(client, ip) { ... }   裸 xray-core config.json
//   - function buildInstallScript(token, origin) { ... }  一鍵安裝 PowerShell 腳本
//   - function buildClashConfig(clients, ip) { ... }  完整 Clash config.yaml
//   - const RULES_BODY = `...`  628 條分流規則本體(從 Shadowrocket 遷移)
//
// 完整版本見「Cloudflare KV Worker 訂閱自動更新 建置指南 v2.md」,之後直接整段貼回這裡。

部署後,到 Worker 的「設定 → 繫結」,新增 KV 命名空間繫結。變數名稱設為 VPN_SUB。

路徑不可以使用 UUID。用 [guid]::NewGuid().ToString("N") 獨立產生路徑。路徑和 UUID 完全無關。

3. 更新 DDNS PowerShell 腳本

在原本「更新 Cloudflare A 記錄成功」的程式碼後面,加入 Update-SubscriptionKV 函式。函式把目前 IP PUT 到 KV 的 current_ip key。

點擊展開/收起:DDNS 腳本新增段落(佔位,稍後貼回)
// ===== DDNS 腳本新增段落(佔位,稍後貼回)=====
// function Update-SubscriptionKV { param($NewIP, $AccountId, $NamespaceId, $ApiToken) ... }
// 呼叫 Cloudflare API: PUT /accounts/{id}/storage/kv/namespaces/{id}/values/current_ip
// 完整程式碼見建置指南 v2.md 第三節。

4. 一鍵安裝腳本的使用方式

Windows 桌機直接執行 xray-core(不透過 App)時,可以在資料夾中(已放好 xray.exe)執行:

irm https://auto-update.doggycxj.com/{token}?v=install | iex

腳本會自動執行下列動作:檢查 xray.exe 是否存在 → 從 ?v=xrayclient 端點下載最新設定,寫入 config.json → 找到同資料夾中舊的 xray 行程並關閉 → 用新設定重新啟動,並顯示 SOCKS5 監聽位址(127.0.0.1:10808)。任何一步失敗時,腳本會顯示明確的錯誤訊息並暫停視窗。

5. 驗證

  • v2ray 格式:解碼 base64 後,應該得到正確的 vless://... 連結。連結中的 IP 是最新的
  • clash 格式:檢查 proxies 區塊的 server 是否為最新 IP
  • xrayclient 格式:JSON 語法正確
  • install 格式:顯示 PowerShell 腳本的原始文字(瀏覽器不會執行腳本)
  • IP_TOKENS:直接顯示純文字 IP,不含其他資訊
  • App 端設定「訂閱自動更新」。建議間隔為 15~30 分鐘

日常維運 SOP

新增一個朋友(單一節點)

  1. config.json 的 clients 加入一組新 UUID,再存檔並重啟 Xray
  2. Worker 的 CLIENTS 加入一行 { uuid, sid, name },再重新部署
  3. 把訂閱網址(不是 QR code)私下傳給新朋友

新增一組多節點群組(例如 direct + warp)

  1. config.json 加入兩組 UUID,對應不同的 email。兩組使用不同的路由分流,再重啟 Xray
  2. Worker 的 CLIENTS 加入群組格式 { clients: [ {...}, {...} ] },再重新部署
  3. 訂閱後 App 端會看到兩個可選節點

停用一個朋友

順序相反。先移除 Worker 的 CLIENTS(訂閱立刻失效),再重新部署。然後刪除 config.json 裡的 UUID,並重啟 Xray(徹底收回連線權限)。

IP 變動

不需要手動處理。DDNS 腳本自動處理,KV 自動更新。四種格式都即時讀取同一個 KV 值。

調整 Clash 分流規則

規則寫在獨立的 RULES_BODY 常數裡。修改後,存檔並重新部署即可。這不影響其他三種格式。

安全性重點提醒

  • 訂閱網址等同完整的連線憑據。解碼後包含完整 UUID。必須透過私下的一對一管道傳遞。不可以公開貼出。
  • ?v=xrayclient / ?v=install 格式也包含完整 UUID 和目前 IP。敏感等級相同。
  • IP_TOKENS 路徑不含 UUID,但會洩漏真實 IP。IP_TOKENS 路徑也必須使用隨機路徑。
  • 路徑建議至少 32 字元([guid]::NewGuid().ToString("N"))。每個朋友使用獨立的一組路徑。
  • 懷疑外流時:先移除 Worker 中對應的那一行,讓訂閱立即失效。再刪除 config.json 的 UUID,並重啟 Xray

是否保留 DDNS 網域

要,繼續保留。訂閱機制上線後,朋友端不再依賴網域。但是,建議 DDNS 腳本照常運作。原因有兩個。第一,如果自己的裝置仍然用網域連線,就需要 DDNS。第二,DDNS 可以當備援。Worker 或 KV 出問題時,DDNS 網域至少是一個人工可以查詢、可以排除問題的管道。兩條線並行,互不影響。成本幾乎是零。

待辦清單

  • 建立 KV namespace,記錄 Namespace ID 和 Account ID
  • Token 加上 Workers KV Storage:Edit 權限
  • 部署 Worker(四種格式版),先放一個朋友測試
  • Worker 綁定 KV(變數名 VPN_SUB)
  • 手動寫入一筆 current_ip 測試值到 KV,驗證四種格式都能正確輸出
  • 修改 DDNS PowerShell 腳本,加入 Update-SubscriptionKV 呼叫
  • 觸發一次 IP 變動,確認 KV 已被自動更新
  • Shadowrocket / Clash App 實測訂閱,確認能正常連線
  • 桌機實測 irm ...?v=install | iex 一鍵安裝流程
  • 開啟訂閱自動更新,間隔設為 15~30 分鐘
  • 其餘朋友依 SOP 逐一加入
  • 【待補】把 Clash RULES_BODY 裡刪減的 628 條規則貼回