跳轉至

Sandbox Gateway

概述

Sandbox Gateway 是基於 Caddy 2.9 的輕量級動態反向代理,專門為 OpenHands 的沙箱環境提供穩定、安全的入口。佢嘅核心職責係將外部請求動態路由到對應嘅 sandbox 實例,避免每次建立 sandbox 都要手動暴露端口或修改防火牆規則。喺呢個架構入面,Sandbox Gateway 扮演「總閘」角色:所有進出 sandbox 嘅 HTTP/HTTPS 流量都經過呢個統一節點,再由 Caddyfile 定義嘅規則轉發到目標容器。

呢個服務係用 Docker Compose 部署,採用官方 caddy:2.9-alpine 映像,確保細小、快速同低資源消耗。佢被設定為 container_name: sandbox-gateway,並加入外部網絡 cf_network,擁有固定 IP 172.21.0.58,方便其他容器或 Cloudflare Tunnel 直接指向佢。

架構

Sandbox Gateway 位於整個系統嘅邊緣層,上游係 Cloudflare Tunnel 或直接對外嘅 Caddy 端口,下游就係動態生成嘅 OpenHands sandbox 容器。由於 OpenHands 每次會為用戶建立獨立 sandbox,呢啲 sandbox 通常冇固定 IP 或對外端口,因此需要 Gateway 根據請求 header、路徑或子域名,將流量轉發到對應嘅 sandbox 端口。

喺實際部署入面,cf_network 係一個外部預建網絡(external: true),由 Cloudflare Tunnel 或其他服務共用。Sandbox Gateway 指定 ipv4_address: 172.21.0.58,確保 IP 唔會因為容器重建而改變。Caddyfile 利用 Caddy 嘅反向代理功能,透過 Docker DNS 或靜態 IP 動態定位 sandbox 目標。

流量流程大致如下:

Client -> Cloudflare Tunnel -> Sandbox Gateway (172.21.0.58:443)
    -> Caddy route -> sandbox-xxxx:port

呢種設計令 sandbox 本身可以保持內部網絡隔離,只開放必要嘅端口俾 Gateway 訪問,降低攻擊面。

部署

部署好簡單,只需準備好以下兩個檔案:

  1. docker-compose.yml(節選內容如上所示)
  2. Caddyfile(用於定義代理規則)

首先確保 cf_network 已經存在:

docker network inspect cf_network

如果未存在,需要先用以下指令建立:

docker network create cf_network --subnet=172.21.0.0/24

之後將 docker-compose.yml 放入目錄例如 /home/opc/oracle-arm-stacks/sandbox-gateway/,並啟動:

docker compose up -d

啟動後 Caddy 會自動讀取掛載嘅 Caddyfile,並將憑證同設定分別存入 caddy_datacaddy_config 兩個 Docker volume。呢兩個 volume 保證容器重啟或更新後,TLS 憑證同設定仍然保留,唔會重複申請或遺失。

配置

Caddyfile 係成個 Gateway 嘅靈魂。一個典型配置範例如下:

sandbox.example.com {
    reverse_proxy * 172.21.0.58:8080
}

但由於 OpenHands sandbox 係動態建立,我哋通常會用 path 前綴或 query 參數嚟區分唔同 sandbox。例如:

*.sandbox.example.com {
    @sandbox {
        header_regexp Host ^([^.]+)\.sandbox\.example\.com$
    }
    reverse_proxy @sandbox 172.21.0.{path.0}:{http.request.port}
}

實際設定要結合 OpenHands 嘅 sandbox 命名機制。如果 sandbox 容器名稱格式係 sandbox-<id>,可以透過 Docker API 或目錄綁定嚟動態取得目標 IP。Caddy 2 支援 caddy-docker-proxy 插件,可以直接從 Docker socket 自動發現容器並產生路由,但使用呢個插件需要額外掛載 /var/run/docker.sock,增加安全風險,所以而家呢個部署並冇使用,而係靠外部機制(例如 OpenHands 回調 API)更新 Caddyfile 並 docker exec sandbox-gateway caddy reload

另外,因為時區設定為 TZ=Asia/Hong_Kong,日誌時間會以香港時間顯示,方便排錯。

維運與監控

日常維運主要集中喺以下幾個方面:

  • 容器狀態:用 docker ps 檢查 sandbox-gateway 是否運行中。因為有 restart: unless-stopped,一般情況下會自動重啟。
  • 日誌:用 docker logs -f sandbox-gateway 查看 Caddy 日誌,特別注意 TLS 憑證續期錯誤或者 proxy 目標不可達嘅錯誤。
  • 配置重載:每次修改 Caddyfile 之後,執行 docker exec sandbox-gateway caddy reload 套用新規則,而唔需要重啟容器。
  • 網絡監控:檢查 172.21.0.58 能否從 Cloudflare Tunnel 容器 ping 通,以及端口 443 是否監聽正常。
  • 資源使用caddy:2.9-alpine 非常輕量,通常少於 50MB RAM。如果發現異常飆升,可能要檢查 sandbox 數量係咪過多,或者有冇 loop 請求。

建議設定 Prometheus 監控 Caddy 嘅 caddy_http_requests_total 指標,不過而家冇裝 exporter,可以用簡單嘅 docker stats 頂住先。

常見問題

Q:Sandbox Gateway 啟動失敗,顯示 network not found?
A:因為 cf_networkexternal: true,必須事先手動建立。執行 docker network create cf_network 再重試。

Q:容器重啟後 IP 變咗?
A:我哋已經指定 ipv4_address: 172.21.0.58,只要網絡子網係 /24 並且冇衝突,就唔會變。

Q:Caddyfile 改完但冇生效?
A:記住要執行 docker exec sandbox-gateway caddy reload,或者直接 docker compose restart sandbox-gateway,但後者會短暫中斷服務。

Q:Sandbox 之間能否互相訪問?
A:如果佢哋都喺 cf_network 入面,理論上可以。建議用防火牆規則或網絡策略隔離,只允許 Gateway 訪問 sandbox 端口。

Q:Caddy 會唔會自動申請 TLS 證書?
A:如果 Caddyfile 使用咗域名而冇指定內部證書,Caddy 喺 2.9 版本會自動向 Let's Encrypt 申請證書,並且存放在 caddy_data volume 入面。內網環境就建議用 tls internal 指令。

相關鏈接

來源

自動生成(2026-08-19 容器覆蓋率補完第二批)