命名空間對照 · network_mode 決策 · 反代 WebSocket · allowedOrigins · 六步 Runbook
在 VPS 上用 Compose 跑 OpenClaw 的自建維護者經常遇到一種錯覺:docker compose ps 全綠、Gateway 日誌也在刷,但本機或旁路容器裡的 openclaw CLI 就是握手超時或 502。根因幾乎總是落在網路命名空間與監聽地址的組合上,而不是模型密鑰本身。本文給誰遇到什麼問題一句話定位,用三層症狀樹把「進程在跑」與「真可達」分開;中間用對照表收斂 bridge、host 與 network_mode: service;再用六步可復現 Runbook把埠發布、迴環綁定、反代 WebSocket 與 allowedOrigins 串成閉環;最後附可引用參數事實與決策矩陣。Compose 基線與資源上限請交叉閱讀 Docker Compose 生產基線,多實例隔離見 同機多實例防串臺,Gateway 加固清單見 生產加固清單;需要節點與出口穩定性可走 訂購頁。
Compose 的 healthcheck 往往只探針容器內迴環或進程存活,它不自動證明「從 CLI 容器到 Gateway 服務名」這條路徑在 DNS、iptables、用戶態代理三層都成立。下面五條在工單裡總是一起出現,把它們拆開,你的排障日誌會立刻變薄。
監聽在 127.0.0.1:Gateway 只綁迴環時,同 bridge 的其他服務用服務名訪問會得到連接拒絕;症狀像隨機超時,實則從未出本網路命名空間。
CLI 跑在宿主機卻抄了容器內地址:把 openclaw-gateway:18789 寫進宿主機 shell 配置,解析與路由立刻錯位。
反代只轉 HTTP 沒轉 Upgrade:瀏覽器或 CLI 走 WSS 時在邊緣返回 400 或靜默斷流,應用日誌卻顯示 Gateway 已就緒。
allowedOrigins 與實際來源不一致:生產域名、內網別名、Tailscale MagicDNS 名稱混用,握手在應用層被拒絕,網路抓包卻「看起來都通」。
network_mode: service 升級競態:共享棧的服務重啟順序變化後,下遊仍連舊 IP 或舊埠映射,表現為間歇性成功。
把下一節的矩陣列印成評審頁:每次架構變更只允許改其中一格,並在變更單附上「同一命名空間內的 curl 與外層對照 curl」兩組輸出,可顯著降低回歸成本。
再補一層「時間維度」:Compose 在滾動更新時會短暫出現新舊容器並存,DNS 緩存與應用連接池若未對齊,就會表現為第一次成功、隨後幾分鐘失敗。此時不要急著調大超時,應先在發起方執行解析刷新與連接復用對照,確認拿到的上遊地址與 docker inspect 裡當前端點一致。若你還疊了用戶態代理或公司透明代理,記得把CONNECT 隧道目標與直連目標分開記錄,避免把代理層的 407 當成應用鑑權失敗。
最後一條容易被忽略:MTU 與分片在跨雲或跨運營商鏈路裡會放大成「偶發超時」;若只有大包失敗而小包健康檢查永遠綠色,應把抓包窗口收窄到單次 WS 幀大小與 TLS 記錄層邊界,而不是先改業務代碼路徑。
當你把上述信號都記錄在變更單後,再打開 openclaw logs 與邊緣訪問日誌做時間對齊,通常能在半小時內把問題從「玄學網路」收斂到單一配置欄位;這也是對外求助時最小復現包應當包含的上下文厚度。
選擇網路模型時,請同時寫下誰發起連接、解析到什麼地址、經過哪些 NAT 層。沒有這張表,團隊會在「改 ports」「改 extra_hosts」「改反代上遊」之間來回橫跳。
| 模型 | 典型監聽寫法 | 同文件其他服務訪問 | 宿主機進程訪問 |
|---|---|---|---|
| 默認 bridge + 埠映射 | 容器內 0.0.0.0 或具體埠發布 | 用 Compose 服務名與內部埠 | 用 127.0.0.1:映射埠 或宿主機網卡 IP |
| host 網路 | 與宿主機共享棧,常等價於綁宿主機可見地址 | 同項目其他容器若不回退 bridge 則不能再用服務名互訪舊路徑 | 與容器並行時優先核對埠衝突與防火牆 INPUT 鏈 |
| network_mode: service:gateway | 與網關共享 netns,迴環視角一致 | 輔助容器可直接打 127.0.0.1:網關埠 | 宿主機仍需走發布埠或反代,不自動繼承 |
真可達的定義是:在發起方相同的網路命名空間裡,用同一組主機名、埠與 TLS 參數重複得到一致響應;而不是「我在筆記本上 curl 通了一次」。
下列順序刻意把「最便宜的觀測」放在最前;任何一步失敗都應停止向下猜測並保存輸出。與 Gateway 安裝語言不一致時,回到 安裝與 doctor 清單 對照欄位名。
確認發起方位置:標註命令運行在宿主機、網關側車容器還是完全獨立的 CLI 容器;輸出 hostname 與 ip route 摘要。
HTTP 層探活:在發起方 netns 內對目標主機名與埠執行 TLS 或明文 GET,核對狀態碼與響應體前綴,排除純 DNS 問題。
WebSocket 探針:用已知可升級路徑發起握手,記錄邊緣與應用返回頭;與應用日誌時間戳對齊。
核對監聽矩陣:在網關容器內檢查監聽地址是否為 127.0.0.1;若是且需要跨服務訪問,改為 0.0.0.0 或引入共享 netns 並同步文檔。
反代四元組:校驗 upstream 指向的是容器 IP 還是 published port、是否透傳 Connection 與 Upgrade、超時是否過短導致長連接被切斷。
應用 origins 收斂:列出瀏覽器、CLI、CI 三類真實 Origin 或等效來源串,與配置逐項打勾;缺一項就視為未完成發布。
docker compose ps
docker compose exec cli sh -lc 'getent hosts openclaw-gateway; curl -fsS -o /dev/null -w "%{http_code}\n" http://openclaw-gateway:18789/health || true'
curl -fsS -o /dev/null -w "%{http_code}\n" http://127.0.0.1:18789/health || true
docker compose logs --no-color --tail=200 openclaw-gateway
提示:將服務名與埠替換為你倉庫中的真實值;若健康路徑不同,保持「同一 URL 在兩層 netns 各跑一次」的方法不變。
這一節只收錄可在代碼與配置裡點名的事實,避免「感覺 CDN 有問題」這類不可審計表述。需要 mem_limit 與日誌輪轉口徑時回到 Compose 生產基線。
ports: 映射在宿主機創建 DNAT 規則;若宿主機本地防火牆策略與 Docker 鏈交互順序理解錯誤,會出現「容器互通但宿主機不通」或反向現象。注意:不要在未記錄基線的情況下同時改反代上遊、Gateway 監聽與 CLI 配置;三角變更會讓回滾無法二分。
把「CLI 與 Gateway 是否必須共享迴環視角」寫成布爾欄位,再決定要不要 network_mode: service: 或 host。矩陣用於評審而不是口號。
| 約束 | 更穩妥默認 | 關鍵驗收 | 主要風險 |
|---|---|---|---|
| CLI 與 Gateway 同 compose 文件 | bridge + 明確監聽 0.0.0.0 | 服務名解析與內部埠 curl 一致 | 忘記同步防火牆與 published 埠文檔 |
| 必須共享 localhost 語義 | sidecar 使用 network_mode: service:gateway | 側車重啟不引入舊連接池 | 升級順序與卷掛載權限耦合 |
| 宿主機已有成熟反代 | 僅 published loopback + 反代 TLS 終結 | 邊緣到上遊的 WS 升級抓包一致 | allowedOrigins 未覆蓋 CLI 使用的 URL 形態 |
長期靠「多疊一層隧道腳本」或「手工改 hosts 救急」會把 MTTR 綁在個人記憶上;一旦上遊證書或內網 DNS 變更,排障會退化成全員會議。相較之下,把可重複命令、監聽矩陣與 origins 列表版本化更像生產系統。
常見誤區:看到 502 就輪換模型密鑰;多數時候應先完成第三節 HTTP 與 WS 兩層探活再動密鑰。
純腳本臨時打通埠而不寫清單,在審計與合規場景下很難證明「默認拒絕、顯式放行」;當 OpenClaw 需要與固定出口、主機名與 mTLS 策略一併歸檔時,自建 VPS 上的 ad-hoc 網路層往往缺少可籤字的變更單。對於要把 iOS 構建、桌面接力與 Agent 常駐放在獨佔、地區與網路檔位可預期環境、並希望減少「宿主機與容器 netns 來回猜」的團隊,VpsMesh 的 Mac Mini 雲端租賃通常是更優解:獨佔節點便於固化監聽與 ACL 敘述,並與 團隊私網 Runbook 使用同一套語言描述邊界;價格與規格見 價格頁,連接與幫助見 幫助中心。