frps,gateway 與 doctor 仍只綁 127.0.0.1;連線先過 auth.token 與各 proxy 的 secretKey,再把兩條健康通道合成單一區域紀錄。與 SSH 反向隧道那篇同一家族:姿態相同,傳輸換成 frp。
邊界常見三選:Tailscale MagicDNS、loopback+SSH -R,或本文 STCP。overlay 被合規擋下、又不想在跳板開 GatewayPorts 時,Visitor 必須帶對 secretKey 才把 TCP 轉進 Mac;兩端埠都綁 loopback。PoP 取捨見 全球入口決策矩陣,公開 TLS 貼邊緣讀 Cloudflare Tunnel 文,上游檢查形狀對照 JumpHost 與合併探針 HowTo。站內公開 CTA:首頁、價格、說明與支援、購買,免登入。
收斂三痛點:拒絕 0.0.0.0 試綁;秘密收斂為 frps auth.token 與每條 STCP 的 secretKey;探針合併讓值班看到「東京紅」而非同根因刷兩頁。
| 關注點 | 作法 | 驗收信號 |
|---|---|---|
| 閘道埠不暴露在公網 | STCP Visitor + frps token | Builder/Visitor 上 ss -ltn 僅見 OpenClaw 在 127.0.0.1 |
| TCP 進 OpenClaw 前先鑑別 | auth.token + STCP secretKey |
金鑰漂移時 frps 拒連計數上升;OpenClaw 存取日誌不因掃描爆量 |
| 區域隔離 | 每 PoP 一組 proxy_name(例 openclaw-sin-gw) |
名稱對錯即失敗,避免誤連他區 |
| gateway + doctor 健康彙總 | 合併 worker 每區 join 兩通道 | 單一區域事件一則告警,非每端點一則 |
frp 角色、埠位與 gateway/doctor 串聯
frps(Linux 堡壘):bindPort = 7000、auth.method = "token" 與長隨機 auth.token;儀表板若開在 7500 請再加 TLS/BasicAuth。7000/tcp 只放行維運網段與各區 Builder 出口 IP,盡量不要對全網。frpc(每台 vpshalo Mac):僅主動連堡壘 7000,註冊兩條 STCP——openclaw-{region}-gw → 127.0.0.1:18080(gateway)、openclaw-{region}-doctor → 127.0.0.1:18081(doctor);各 proxy 獨立 secretKey。Visitor(維運機或合併 worker 上的 frpc):同樣僅主動出站,本機綁 127.0.0.1:28080(閘道)與 127.0.0.1:28081(doctor)。驗證鏈為:curl http://127.0.0.1:28080/healthz → Visitor → frps 校 token → STCP 校 secret → Builder loopback → OpenClaw。gateway 承載推理流量;doctor 回較完整健康 JSON(佇列、模型版本、GPU/Metal 等)。兩路並行才能在「閘道仍 200、doctor 卡住」時被看見。
最小可複現步驟
每區執行一次;{region} 換成庫存標籤(例 sin、tyo、hkg、icn、lax)。
- 1. OpenClaw 綁 loopback:設定
OPENCLAW_HOME(每區隔離),以--gateway-bind 127.0.0.1:18080 --doctor-bind 127.0.0.1:18081啟動;本機curl/healthz與/doctor僅在 localhost 成功。 - 2. 堡壘啟動 frps:
frps -c frps.toml,防火牆/安全群組僅放行維運與 Builder 來源。 - 3. Builder 端 frpc:兩條 STCP、兩個
secretKey,無remotePort(設計上不公開埠)。以 systemd/launchd 常駐並加重啟退避,避免一鬆防火牆。 - 4. Visitor 端 frpc:兩個 STCP visitor,
secretKey與 proxy 對齊;先本機curl再開權限。 - 5. 合併探針:小程式依序打
127.0.0.1:28080/healthz、127.0.0.1:28081/doctor,寫入{region, gw_ms, doctor_ms, status};同一五分鐘窗內兩路徑皆失敗才對該區分頁,多區同時劣化再升級。
# frpc.toml — Builder:兩條 STCP,只對 loopback
serverAddr = "bastion-sin.vpshalo.example"
serverPort = 7000
auth.method = "token"
auth.token = "<long-random-frps-token>"
[[proxies]]
name = "openclaw-sin-gw"
type = "stcp"
secretKey = "<sk-sin-gw>"
localIP = "127.0.0.1"
localPort = 18080
[[proxies]]
name = "openclaw-sin-doctor"
type = "stcp"
secretKey = "<sk-sin-doctor>"
localIP = "127.0.0.1"
localPort = 18081
# frpc.toml — Visitor:兩條通道僅綁 127.0.0.1
[[visitors]]
name = "v-openclaw-sin-gw"
type = "stcp"
serverName = "openclaw-sin-gw"
secretKey = "<sk-sin-gw>"
bindAddr = "127.0.0.1"
bindPort = 28080
[[visitors]]
name = "v-openclaw-sin-doctor"
type = "stcp"
serverName = "openclaw-sin-doctor"
secretKey = "<sk-sin-doctor>"
bindAddr = "127.0.0.1"
bindPort = 28081
0.0.0.0。重點是兩端維持 loopback。三句可貼進 Runbook
- 輪換面小:frps 共用
auth.token,每條 STCP 一個secretKey,比整片ssh_config秘密林好管。 - 掃描打不到 OpenClaw:secret 對齊前 frps 即拒連,失敗計數在 frps,不必用閘道日誌扛掃描噪音。
- 兩端 loopback 是預設值:稽核最愛的「流量落在本機迴環」即為預設姿態;例外少、要審、要留痕。
排障速查
Visitor 連不上:先測堡壘 7000/tcp 與白名單;frps 日誌中 auth failed 多為 token 不一致,STCP 相關拒絕多為 secretKey 漂移——一次只改一個變因。閘道 200、doctor 卡住:多半是 Builder 上模型執行緒失控,doctor 正在盡責;優先重啟 OpenClaw worker,勿先動 frp。延遲高:中繼走 frps 時 RTT 吃緊,請把 Builder 與堡壘放在相近 PoP(選型可對照 SCP/SFTP RTT 矩陣文)。輪換後仍告警:Visitor 仍舊金鑰;維護窗內同步更新 proxy/visitor,再以 curl 127.0.0.1:28080/healthz 確認後靜音。兩探針同一秒同掛:先懷疑隧道或 frps/frpc 監管與 keepalive,而非模型本身。
auth.method、STCP 與 visitor 的 bindAddr。OpenClaw 發行版對 --gateway-bind/--doctor-bind 的拼字亦可能不同,本文述「意圖」而非廠商 SLA;此模式與上文 SSH、Tailscale 文互補而非互斥。
腳本化後,邊界應「刻意無聊」:各區 loopback、經鑑別的 STCP、無公網監聽、行事曆驅動輪換、每區單一合併告警。遠端 Mac 請落在實測過的 PoP,容量、registry 鏡像與 Visitor 一併搬遷。