整體架構

要解決的問題:家用浮動 IP 頻繁變動,中國各地 DNS 快取跟不上,朋友端常常連不上。 解法是讓朋友端不再依賴「網域解析」,改用訂閱功能,App 定時自動抓取目前的最新 IP, 全程不需要人工通知、也不受 DNS 傳播速度影響。

核心是一個 Cloudflare Worker:依網址路徑判斷是哪個朋友/哪組裝置,去 KV 讀取「現在的 IP」, 再依 ?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 是多少」的其他用途用。

目前的伺服器環境

伺服器端 Windows 電腦跑 xray + config.json,實際上有 4 個 inbound:

Inbound監聽用途
① VLESS Reality Vision(對外)區網 IP:443給所有外部朋友直連,主力入口
② VLESS Reality(本機迴環)127.0.0.1:12345客戶端設定裡的迴環測試用,不對外開放
③ VLESS + WebSocket127.0.0.1:8080走 Cloudflare CDN 中轉的備援線路
④ SOCKS(給 WARP 用)127.0.0.1:50000wgcf-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,僅供本機迴環測試
//     // ③ 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 被腳本自動更新「值」,不用再手動碰它。

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.jsonclients 加一組新 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,同樣要用隨機路徑
  • 路徑建議至少 32 字元([guid]::NewGuid().ToString("N")),每個朋友獨立一組
  • 懷疑外流:先移除 Worker 對應那行讓訂閱立即失效,再回頭刪 config.json 的 UUID 並重啟 Xray

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 條規則貼回去