工具
三個應用程式沿互不相交的通道連至各自出口,象徵 VPN Instance 的獨立網路路徑;非即時狀態圖。

工程思考 · 研究筆記

我想做的 VPN Manager:讓不同 App 各走自己的 VPN

我想開發 VPN Manager:為不同 App 與 Service 規劃獨立 VPN Instance、Linux 原生隔離、故障封閉、Provider 自舉,以及流量監控。

VPN MANAGER / 開發筆記

最初想做什麼

主機原本的網路不變。
指定的 App 只走指定出口。

最初會想做 VPN Manager,其實就是覺得一般 VPN 客戶端大多偏向整台電腦一起切換。
但我需要的不是這個。
我想指定哪些 App 走哪條 VPN,沒被管理的程式就繼續使用主機原本的網路。

例如我同時開著瀏覽器、下載程式,以及其他 App。
瀏覽器交給 Instance A,下載程式交給 Instance B,其他則使用原本的網路。
A 和 B 各自有自己的 WireGuard identity、DNS、Gateway、連線資源和生命週期。

如果 A 斷線,我寧願瀏覽器直接斷網。
它不能自動跑去 B,更不能退回 ISP 原本的出口。

瀏覽器受管應用程式
Instance A身分 A/DNS A
WireGuard 對端 A獨立 VPN 出口
下載程式受管應用程式
Instance B身分 B/DNS B
WireGuard 對端 B另一個獨立出口
其他 App 等未納管應用程式
主機原有網路維持原本路由
原有網路不受 VPN Manager 修改

如果 A 斷線:瀏覽器就沒有網路。
Instance B 和沒被管理的程式照常運作,不需要跟著切換。

使用情境|同一台主機的三條不同路徑(小螢幕可左右滑動)。這是預期的架構行為示意,而非即時連線畫面。

我還希望可以把不同 VPN 供應商的帳號、Profile 和 Gateway 放在同一套系統裡管理。
指定的 App 或 Service 最好能直接從 OS 的網路層隔離,不用 Docker,也不用修改整台電腦的 default route。

流量資訊也是我想做的功能。
我想看每個 Instance 用了多少流量、哪些 Gateway 正在塞車、DNS 花了多久,還有哪個程序吃掉最多 CPU 或記憶體。
如果只有一個 Connected,我覺得意義不大。

類似的做法其實已經有人做了,也有不少人自己用 netns、Proxy 和 firewall 拼出需要的環境。
但我想把多條 VPN 的管理、App 隔離、故障恢復和監控放在一起,不用每次都自己接一堆東西。

先從整個系統架構開始。

目前的操作畫面

VPN Manager 總覽:兩條 VPN 連線、各自本機 Proxy Port、下載上傳統計與流量路徑圖
畫面 01VPN Manager 總覽:兩條連線、各自的代理埠,以及流量路徑。實際介面截圖・2026-11-01 (可左右滑動)
VPN Manager 連線頁:荷蘭與香港兩條 WireGuard 連線,包含連線狀態、代理埠、即時流量與資源監測
畫面 02連線頁:每條連線的狀態、即時流量與資源資訊。實際介面截圖・2026-11-01 (可左右滑動)

01整個系統的主幹

完整系統架構 VPN Controller只交意圖;Instance Manager獨立管理Instance。所有持久資料經Store helper到Store;資料流不經管理面。 圖 1|VPN Manager 全系統:控制、資料、持久化與觀測 網頁資源服務 提供 React 靜態資源/同源 React 使用者介面 核心操作/供應商/效能面板 靜態資源 HTTP/SSE VPN 供應商管理器 Mullvad/AIRVPN 介接器 各供應商 IP 出口檢查 候選設定檔與狀態 VPN 控制器 VPN Core/Web API VPN 平台控制協調器 Profile 驗證/Store helper 只負責操作意圖協調 安全策略管理器 DNS 設定檔驗證 防火牆策略/自動封鎖 IP 封鎖清單政策 設定檔 策略 效能管理器 分析/基準測試工作階段 比較/效能報告 Instance 管理器 唯一生命週期管理權/外層監控 世代、資源租約與自動恢復 平台管理器 Linux/macOS 系統介接 OS 權限/沙箱/資源控制 帶型別的生命週期意圖 明確授權的效能測試 測試租約 作業系統請求 指標服務 指標收集器 指標壓縮模組 VPN Instance A … N 各自擁有完整內部服務 獨立 GotaTun/DNS/Gateway App 流量不經 Controller Store helper 共用型別安全的持久化客戶端 設定/啟動/開通/停止 檔案描述符(FD) 監控指標 有界資料查詢 持久化指標與報表一律經 Store helper Store 儲存服務 唯一 SQLite 存取者/內部模組 SQLite 控制資料庫+指標資料庫 受管 App Gateway 用戶端 VPN 對端節點 已加密 WireGuard UDP 藍:控制 綠:資料 黃:OS 資源 紫:觀測 所有持久化透過 Store helper;秘密資料使用獨立的私密傳遞通道。
圖 1VPN Manager 完整系統架構控制面、資料面、觀測與持久化分離。(可左右滑動檢視完整圖表)

整體控制路徑先這樣規劃:

React UI→VPN Web API / VPN Core→Instance Manager→Instance Controller

這裡我把 Instance Manager 做成獨立程序。
所有 Instance 的啟動、停止、generation、資源租約和恢復都交給它。
Controller 只接收 UI/API 的操作意圖,不去轉送 App 的 TCP/UDP 資料。

要動到 OS 權限的部分就交給 Platform Manager。
不管是 network namespace、process sandbox、FD、firewall policy,還是 macOS 的 capture/deny,都由它負責。
我不希望其他元件因為方便,就直接跑去改系統網路設定。

Store 負責把狀態存下來,Metrics 收集數據,Performance Manager 再處理分析與授權的測試。
這些東西不要卡在 App 的封包路徑上。
例如 Metrics 或資料庫寫入變慢,不能因此讓正在傳送的封包排隊;新的狀態變更則照原本的封閉規則處理。

表 1|執行邊界與主要責任
執行邊界 主要責任
vpn-controllerd 提供 React 靜態資產、VPN Web API、VPN Core,以及 Provider/Security/Metrics/Performance 控制協調。
vpn-instance-managerd 跨 Instance 唯一生命週期 owner;管理 desired state、generation、identity/resource lease、外層 Watchdog 與復原對帳。
vpn-platformd 獨占高權限 OS 操作;執行 Linux/macOS Adapter、sandbox、FD/policy 建立、spawn、seal 與安全證據蒐集。
vpn-stored 唯一 SQLite owner;管理 control.sqlite、metrics.sqlite、secret、revision、operation journal 與備份。
vpn-instance × N 每條 VPN 的獨立 worker;擁有自己的 GotaTun、DNS、Gateway、Port、Metrics 與內層 Watchdog。
vpn-provider-worker 按 Provider job 執行 API 操作、route-bound IP preflight 與受限 connector,不自行建立或啟停 Instance。
macOS system extension(若啟用) 處理受管 App 的 flow capture、deny 與 bridge;依原生平台能力提供安全邊界。

完整的元件歸屬

元件我先依照誰負責管理、誰有權限操作來分類。
光是畫一堆方塊沒什麼用,重要的是某個程序掛了,會影響到誰,以及誰可以把它重新啟動。

完整元件歸屬圖 55個正式元件全部列入;同名Process Manager、Instance Watchdog依父層區分。圖的縮排表示歸屬,不代表每個helper都是daemon。 元件歸屬|依執行邊界與權限責任分組 React 使用者介面(UI - React) · 核心介面(Core UI) · 效能面板(Performance Panel) · 供應商管理面板 VPN 控制器(VPN Controller) · VPN 核心(VPN Core) · VPN Web API · VPN 平台控制協調器 · VPN 設定檔驗證器 · Store helper(儲存介接) 平台管理器(Platform Manager) · Linux 系統介接器 · 程序管理器 · 程序沙箱 · 網路資源控制 · macOS 系統介接器 · 程序管理器 · 程序沙箱 · 網路資源控制 供應商管理器(VPN Provide Manager) · Mullvad 供應商介接器 · Mullvad IP 出口檢查器 · AIRVPN 供應商介接器 · AIRVPN IP 出口檢查器 安全管理器(Security Manager) · DNS 設定檔驗證器 · 防火牆設定檔 · 自動封鎖偵測器 指標服務(Metrics Service) · 指標收集器 · 指標壓縮模組 效能管理器(Performance Manager) 儲存服務(Store) · 設定資料輔助模組 · 秘密資料輔助模組 · 安全政策輔助模組 · DNS 設定檔輔助模組 · 供應商資料輔助模組 · Mullvad 資料輔助模組 · AIRVPN 資料輔助模組 · 指標儲存輔助模組 實例管理器(Instance Manager) · 外層 Instance 監控器 · VPN Instance(單一 Profile) · Instance 控制器 · Instance DNS 控制器 · Instance 埠控制器 · 埠轉發(Port forward) · Instance 指標 · Instance 內層監控器 · Gateway 管理器 · Gateway 服務 · Gateway 指標 · GotaTun 網頁靜態資源服務 依元件所有權、權限及故障隔離邊界決定執行位置。
元件歸屬圖完整元件與責任歸屬依 parent/owner 分組,展示 UI、Controller、Platform、Store 與各個 Instance 內部的元件。(可左右滑動檢視完整圖表)

02VPN Instance 架構

單一Instance完整內部與資料路徑 每個Instance都含自己的Controller、DNS、Port、Gateway、Metrics、Watchdog與GotaTun。內層Watchdog可封鎖,不能自行重建或解封。 圖 2|單一 VPN Instance:獨立服務與資料路徑 Instance 管理器 下發命令/執行世代/資源租約 VPN Instance|獨立 Rust Worker Instance 控制器 只控制本 Instance Gateway 管理器 Gateway 服務 × N Gateway 指標 Instance DNS 控制器 獨立快取/連線池/解析器 DNS 僅透過 VPN 通道 Instance 埠控制器 埠轉發(Port forward) 僅允許同 Instance 的 App 指定的受管 App Proxy 用戶端/ 受保護的程序 埠轉發僅送到同 Instance 的 App TCP/IP 處理+GotaTun Linux 核心/macOS Rust 協定堆疊 獨立 WireGuard 裝置與金鑰 Instance 指標 本地計數器/延遲分布 Instance 監控器 通道/DNS/平台政策健康狀態 VPN 對端節點 限定對端的加密 WireGuard UDP 平台管理器 程序沙箱/TUN/ 受限 UDP FD 指標服務 有界的快照資料傳送 App 無法取得主機 Underlay、秘密資料、Store 或 namespace 描述符。
圖 2單一 VPN Instance 的服務與資料路徑每個 Instance 擁有自己的 runtime、控制器、Gateway、DNS、Metrics 與 Watchdog。(可左右滑動檢視完整圖表)

每條 Instance 都有自己的 GotaTun、DNS Controller、Port Controller、Gateway Manager、Metrics 和 Watchdog。
WireGuard identity、DNS cache、socket、buffer、queue 也都要分開。
CPU、NIC 和 OS 可以共用,但 A 的執行狀態不應該和 B 混在一起。

有個地方要先講清楚。
GotaTun 是 WireGuard 引擎,本身不是完整的 TCP/IP socket stack。
所以接上 GotaTun,不代表 TCP/UDP 連線處理就全部有了,這部分還是得另外處理。

Linux 我傾向直接用隔離 network namespace 裡的 kernel TCP/IP stack。
macOS 的顯式 Proxy 則由每條 Instance 自己使用 smoltcp 加上 GotaTun。
各自的 socket、buffer、queue 也要獨立,不要讓 Controller 的 SQL 或 Provider HTTP 呼叫卡到真正的網路流量。

DNS 也要跟著 Instance 走。
解析失敗就回報失敗,不能偷偷改問 host resolver。
Gateway 收到 HTTP CONNECT 或 SOCKS5 TCP/UDP 後,要真的交給自己的 Instance 建立目的地連線。
Port Forward 只能轉到同一個 Instance 裡已驗證的 App endpoint,不能為了省事直接接到 host 的 127.0.0.1。

受管 App、Gateway 和 Port Forward 的差別

我把流量入口分成三種。
受管 App 要先進入隔離環境,它自己不能選 host 網路。
Gateway 只負責明確交給 HTTP/SOCKS Proxy 的流量,App 另外建立的連線不會自動受到保護。
Port Forward 則是從 VPN 進來的流量,只能送到同一個 Instance 裡有有效 AppEndpointLease 的 App。

DNS 和 IPv6 也不能有特例。
如果 Instance 的 DNS 路徑不可用,那就不查。
IPv6 如果沒有能驗證的 tunnel 路徑,也不能自動放它走主機網路。

macOS 的 App 隔離比較麻煩

macOS 這邊其實比較麻煩。
顯式 Proxy 可以做,但它只管真正交給 Proxy 的流量。
像 QUIC、WebRTC,或 App 自己使用的系統 DNS,都可能另外建立 socket。
所以有 Proxy,不代表整個 App 已經隔離。

瀏覽器工具箱的網站代理路由頁:香港 SOCKS5 127.0.0.1:1080 與荷蘭 SOCKS5 127.0.0.1:1082 兩個代理設定檔
畫面 03瀏覽器工具箱的網站代理路由:香港使用 127.0.0.1:1080,荷蘭使用 127.0.0.1:1082。實際介面截圖・2026-11-01 (可左右滑動)

03Linux:從 OS 層做到「無路可退」

Linux隔離資料路徑 host預建受限UDP FD只交GotaTun;App只有netns內lo/TUN路徑。worker換代可保留封閉sandbox,不改主機default route/DNS。 圖 3|Linux:受管程序隔離與 WireGuard UDP 出口 主機網路 namespace|既有網路設定維持不變 Instance 隔離沙箱:僅 lo 與 TUN,沒有 veth/Host NAT 主機 loopback 監聽端 Gateway TCP/UDP 轉送 只接受已綁定的用戶端流量 程序沙箱 指定的受管 App 程序樹 禁止主機 IPC 與繼承網路 FD Instance 內部服務 Gateway/DNS/埠連線 目的地 socket 建立於隔離 netns 已預先綁定的監聽 FD 交付 Linux 核心 TCP/IP+TUN 獨立路由/DNS/防火牆策略 GotaTun 每個 Instance 擁有獨立裝置 受限 UDP FD 預先建立於主機 netns 只能發送到核准的 VPN peer 主機網卡 → VPN 對端 平台管理:程序與網路資源控制 Worker/TUN 故障時,App 仍沒有其他外網出口;沙箱生命週期可跨越 Worker 世代。 只建立或清除本系統擁有的 namespace、cgroup、bind 與過濾規則。
圖 3Linux namespace 隔離與 WireGuard UDP 路徑一般 host 網路不變;隔離 netns 的 App 沒有未經授權的明文 host 出口。(可左右滑動檢視完整圖表)

Linux 的做法比較直接。
我不打算修改主機的 default route,也不會把實體網卡搬去別的 namespace。
沒有被管理的 App 照常使用原本的網路。

Platform Manager 先在 host network namespace 建立只允許指定 WireGuard peer 的 UDP socket。
接著把受限的 FD 交給隔離 namespace 裡的 VPN worker。
那個 namespace 只有 loopback 和 TUN,不提供通往 host 的 veth/NAT 明文出口。

App 送出的 IP 封包先進 TUN,由 GotaTun 加密,再透過原先在 host namespace 建立的 UDP FD 送到 WireGuard peer。
不過,光是 socket 在 host 建立還不夠。
它可以連去哪個 IP/port、FD 由誰持有,以及 Platform policy 是否真的生效,這些都要確認。

我比較在意的是,App 根本沒有普通的 host internet 出口。
worker 掛掉就先斷網,沒必要替它找備用路線。
我不能接受 VPN 斷線以後,App 自己繞回 ISP 出口。

但 netns 也不是完整的 sandbox。
App 可能繼承了其他程序的 FD,或透過 Unix socket、D-Bus、host IPC 找到旁路。

04Instance 的啟動與故障恢復流程

生命週期、自動恢復與停止優先 manual Stop與急停優先於恢復;Manager/intent/generation/sandbox全tuple匹配後才能CommitResume。Manager換代替換worker,只收養closed sandbox。 圖 5|安全啟動、自動恢復與人工停止優先權 持久化意圖與資源保留 期望狀態/人工停止/緊急停止 Manager 任期/意圖版次 Worker 世代/身分租約 先封閉環境,再啟動程序 沙箱世代獨立於 Worker 世代 未設定 Worker/已驗證身分 Store 私密交付一次性秘密 僅允許健康探測 驗證 VPN 通道/DNS/策略 關閉 App/Gateway/埠轉發 獨立驗證健康狀態 提交開通(CommitResume) Manager 重新核對最新意圖 Platform 消耗單次授權 此步驟才正式打開流量閘門 就緒/僅走 VPN 通道 啟用已設定的 App/Gateway 只允許當前 Worker 世代 Controller 故障不影響管理器 故障 → 封閉/封存 立即關閉相關資料入口 故障偵測時沒有直接出口 已封存世代不可重新開通 自動恢復 僅當持久意圖為 desired=running 人工停止/緊急停止必須已清除 舊 Worker/FD 必須確實失效 新增世代,沿用 Instance ID 人工停止/緊急停止 推進意圖版次並撤銷授權 過期恢復程序不可重新開通 解除緊急狀態仍保持停止 其後必須由使用者明確啟動 Manager 或 Platform 重啟 封存舊世代 僅保留已證明封閉的沙箱租約 更換執行中的 Worker 停止意圖無法證明 → 封閉 只有 Instance Manager 能核准 CommitResume;單獨 ApplyPolicy 無法重新開通。 CPU/Store/Metrics 暫停不得產生非授權的主機直連備援。
圖 5Instance 的啟動與故障恢復流程圖中的 Resume 需要當代意圖、worker generation 與 Platform enforcement 證據。(可左右滑動檢視完整圖表)

WireGuard 握手成功,不代表我就可以讓 App 開始上網。

啟動 Instance 時,先把隔離環境建好,而且預設封閉。
worker 起來後,只允許 WireGuard 握手、DNS 和健康探測。
等目前的設定、Platform policy 和 worker generation 都確認沒問題,再把 App 和 Gateway 打開。

中間任何一步失敗,就維持 blocked。
重建 worker 時一定要換新的 generation,被 Seal 的舊 generation 不能再開。
Manager 換代、Platform epoch 變更,或使用者在這期間按了 Start/Stop,先前發出的命令都不能再生效。

Watchdog 我分成兩層。
Instance 裡面的 Watchdog 發現問題就先把自己的 ingress 關掉,然後回報故障。
外面的 Instance Manager 才負責記錄意圖、回收舊資源和重建。
我不想看到兩邊同時搶著 restart 同一個 Instance。

手動 Stop 和 EmergencyStop 的優先權一定要最高。
假設 Stop 的時候資料庫剛好壞掉,連最新的停止意圖有沒有成功保存都不知道,系統就不能拿舊的 desired=running 自動開回來。
這時我寧願進入 recovery_required,等人確認。

至於原本的 TCP session 能不能在 crash 後接回來,我沒有要硬保證。
讓連線斷掉,比走錯出口好。

連線狀態不能只有 Connected/Disconnected

我不希望 UI 只有 Connected/Disconnected 兩種狀態。
例如我把 A 設成 desired_state=running,但它目前正在 reconnecting,而且 enforcement=blocked。
這三件事應該分開顯示。
我想讓它繼續運作,跟它現在能不能外送,是不同的事情。

啟動、故障封閉與自動恢復:START/ACTIVATE 循序圖

流程會先把 desired=running 寫進 Store,Manager 再保留 generation 和 identity lease,請 Platform 執行 PrepareClosed。
worker 先以 probe_only 啟動。
確認 tunnel、DNS、policy 和當前的權限資訊都一致後,才執行 CommitResume 和 Activate。

START/ACTIVATE 循序圖 所有 payload gate 預設關閉;只有當代 Manager 與 Platform 證據可授權開通。 START/ACTIVATE 啟動與開通循序圖 資料閘門預設關閉;只有當代 Manager 與 Platform 的驗證證據能核准開通。 使用者介面 VPN 核心 儲存服務 Instance 管理器 平台服務 Instance Worker 01 · 啟動+版本比對 02 · CAS 持久化 desired=running 03 · 發出啟動意圖 04 · 保留 Worker 世代與金鑰租約 05 · PrepareClosed:先封閉 06 · 回傳沙箱/策略證據 07 · 建立 Worker 與受限 FD 08 · 交付受限資源並啟動 09 · 單次秘密租約交付 10 · Configure/Start:僅探測 11 · VPN 通道與 DNS 驗證完成 12 · CommitResume:核准開通 13 · Activate:正式就緒 14 · 操作成功 15 · SSE 回傳最新狀態
循序圖 ASTART/ACTIVATE 循序圖從持久化意圖、封閉環境到 probe-only,最後才授權 Activate。(可左右滑動檢視完整圖表)

05第一次 Provider 要怎麼建立?這是一個自舉問題

Provider首次連線與每次訪問檢查 首次取得Profile即自動建立Instance,撤銷原網路後封存latch。所有Provider共用人工選定出口,但每個Adapter各自檢查且每次HTTP重做preflight。 圖 6|Provider 首次自舉、切換出口與每次請求驗證 首次 Provider 建立作業 單一帳號/僅授權受限主機網路 10 分鐘授權/單次 60 秒工作階段 每次 API 請求仍須執行檢查 取得首份合法 Profile 驗證器與持久化唯一子操作 控制器 → Instance 管理器 自動建立並啟動 Instance 新 Instance 通過初步探測 獨立通道/DNS/系統限制 候選連線只能用於健康探測 封閉原始直連出口 1.持久記錄封閉意圖 2.撤銷全部直連 socket 3.寫入永久鎖定與出口綁定 全域選定的 Instance 所有 Provider 共用同一出口 只能人工切換或停用 不得自動回退主機直連 封鎖/停用 仍顯示原本選定的 Instance 過期監控資訊不可視為正常 恢復不可覆蓋人工停止 每一個實際 Provider API 請求:含重試、分頁、權杖更新與對帳 1.規劃並保留配額 固定 IP 家族與不可變請求 保留 IP 探測與 API 配額 讀取當前連線身分 2.Provider IP 出口檢查 與 API 使用相同連線/IP 家族 分別核對 IP、地理與供應商歸屬 探測請求不帶帳號憑證 3.核發單次請求許可 綁定請求、路由與連線世代 隨機值+2 秒發送期限 檢查流程不遞迴呼叫自身 4.發送前原子驗證 重驗世代、IP 家族與期限 首個 API 位元組前消耗許可 不允許自動轉址或隱藏重試 5.執行 Provider API 僅由選定的 VPN 通道送出 遠端變更結果不明 → unknown 先對帳,再決定是否重試 Provider 管理面板 Instance 離線也保留選擇 出口 IP/國家/城市/時間 供應商歸屬可能無法確認 IP 觀測不能證明 DNS、IPv6、QUIC 或所有 App 路徑;必須由平台限制強制保護。 完成切換後:禁止主機 DNS、主機 HTTP 與自動改用其他出口。
圖 6Provider 第一次自舉、切換出口與每次請求的前置檢查首次自舉的受限直連權限,在切換至 VPN 後被撤銷,不允許自動 fallback。(可左右滑動檢視完整圖表)

Provider 也有個問題。
剛安裝 VPN Manager 的時候,根本還沒有 VPN Profile,我總得先去 Mullvad 或 AIRVPN 取得帳號、device 和 WireGuard 設定。
那第一個管理請求要走哪裡?

我目前的想法是只允許第一次有條件的直連。
Provider worker 拿到限時、限帳號、限 HTTPS origin、DNS 與流量預算的 BootstrapGrant。
拿到第一份合法 Profile,就由 Controller 要求 Instance Manager 建立並啟動第一條 VPN。

確認 tunnel 已經能處理管理請求後,先把封閉 direct 的意圖寫進 Store,再撤銷原本的 grant 和 socket,最後才標記 bootstrap_consumed=true,並設定 Provider 的全域出口。
這個順序不能亂,尤其不能在直連還活著的時候,就說已經切換完成。

之後所有 Provider API 都走使用者選定的 VPN Instance。
那條 Instance 掛了,就顯示 blocked,不准切回 host,也不能自動換另一條。
真的處理不了,再由使用者手動選新出口,或明確授權一次性的 rebootstrap。

我還希望每次真正送出 Provider HTTP request 前,都先做一次 IP preflight。
包括 retry、pagination、token refresh,都要確認同一個 route tuple、IP family 和 connector,拿到只供這次 request 使用的 ProviderRequestPermit 才能送出。
目前暫定 preflight deadline 3 秒、dispatch window 2 秒。
這會比較慢,也會增加 checker quota,但至少不會拿 UI 幾分鐘前顯示的 IP 當成現在的選路證據。

UI 要把幾件事情分開顯示:選的是哪條 Instance、這次 request 有沒有真的經過受控 tunnel,以及外部 IP 是不是該 Provider 的出口。
例如我選 Mullvad Instance 去呼叫 AIRVPN 的管理 API,這可以完全符合我的設定。
對外 IP 不是 AIRVPN,不代表流量洩漏。

Provider Adapter 要負責哪些事情

供應商整合我想盡量走同一個流程。
Profile 驗證、Instance 建立、出口綁定由共用的控制邏輯處理;Mullvad、AIRVPN 各自的 device、server 和 port-forward API 才交給 Adapter。
新增 Provider 的時候,我不想每個 Adapter 都有權限直接啟停 Instance 或開 host socket。

Provider API 還有一個麻煩:request 送出去以後 timeout,不代表對方沒有執行。
例如 device 其實建立成功,只是回覆沒有收到。
這時候先記成 unknown,再用 operation journal 查詢遠端狀態,不應該直接重送一次。

PROVIDER 首次自舉循序圖

整個自舉要算完成,必須確認新 Instance 能發出管理請求,原本的 direct 授權也確實撤銷,最後才 CommitEgress。
如果切換中的某個結果無法確認,我寧願先停在 blocked,把狀態查清楚。

PROVIDER 首次自舉循序圖 初次受限直連 → 首 Profile → 自動啟 Instance → seal/revoke → CommitEgress。 Provider 首次建立 VPN 循序圖 初次受限直連 → 首份 Profile → 自動建立 Instance → 封閉直連 → 綁定 VPN 出口。 UI/VPN 核心 儲存服務 平台服務 Provider 工作程序 Provider API 實例管理器 VPN Instance 01 · 建立自舉紀錄 02 · 準備限時直連權限 03 · 僅交付核准的直連通道 04 · IP 出口預檢+取得 Profile 05 · 回傳 Profile 06 · 儲存 Profile 與唯一子操作 07 · 自動建立並啟動 Instance 08 · 封閉環境、建立 Worker 09 · 交付 FD、啟動 Worker 10 · VPN/DNS/管理通道就緒 11 · 持久寫入封閉意圖 12 · 撤銷直連授權與 socket 13 · 回傳撤銷驗證證據 14 · 確認出口與永久鎖定 15 · 後續均透過選定 Instance
循序圖 BPROVIDER 首次自舉循序圖BootstrapGrant → 第一份 Profile → Instance → Seal/Revocation → CommitEgress。(可左右滑動檢視完整圖表)

06我想看清楚每條 VPN 的流量與資源使用

我不希望 VPN Manager 最後只有幾個綠燈告訴我 VPN 已連線。
我想知道哪條 Instance 正在吃流量、Gateway 有多少活躍連線、DNS 延遲有沒有升高,以及 CPU、記憶體和 queue 被哪個程序占用。

Metrics Service 和 Performance Manager 我會分開。
Metrics Service 負責收集統計資料,像 Instance counters、Gateway payload bytes、WireGuard UDP bytes、DNS 成功與失敗、active flows、CPU 和 RSS。
Performance Manager 才負責分析吞吐、延遲、資源效率,或執行我明確啟動的 benchmark。
它不能為了測速就自己改 Instance 的狀態。

流量觀測與效能分析架構 Instance 的本地 counters 非阻塞傳給 Metrics Collector,再壓縮儲存。UI 與 Performance Manager 查詢聚合資料。App payload 不經過這條鏈。 圖 7|流量指標收集與非阻塞觀測鏈 Instance 指標 指標收集器 壓縮與彙總 Store/指標資料庫 效能管理器 React 介面 每秒累積計數器 不轉送封包內容 驗序/去重/缺口標記 過載時可丟棄採樣 CBOR+Zstd 時間彙總/保留期限 控制與指標資料分庫 有界資料查詢 分析/效能基準測試 速率/延遲/資料缺口 觀測鏈只傳統計資料;App/Gateway 的實際流量仍經由各自的 Instance。
圖 7流量資料從 Instance 到 UI 的獨立觀測鏈Metrics 滿載可降低採樣完整度,但不可以因此讓資料面等待;圖表必須標示缺口。

Metrics 最好不要對資料面產生反向壓力。
Instance 每秒送一次有界 snapshot,Collector 驗序、去重,後面再用 CBOR/Zstd 壓縮與彙總。
如果收集端塞住,丟幾筆樣本並標記 gap 就好,不能讓封包等資料庫。

流量數字也不能亂算。
Gateway payload bytes 和 WireGuard UDP bytes 是不同層的統計,不能加起來當總流量。
counter reset 或資料中斷時,圖表要顯示缺口或未知,不能直接畫成 0。
goodput 更要有接收端確認,不能只拿 sender counter 來算。

流量監控也不需要把所有東西都記下來。
預設收 counters、histograms 和必要的錯誤資料就好。
DNS query name、完整 URL 或封包 payload,我不想全部塞進 Metrics。

留言與討論

正在連線到留言服務…