OpenSandbox 实战:在沙箱中拉起 OpenClaw Gateway 并暴露其 HTTP 端点
2026/9/15 7:53:53 网站建设 项目流程

OpenSandbox 实战:在沙箱中拉起 OpenClaw Gateway 并暴露其 HTTP 端点

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

本文基于仓库中的 OpenClaw 示例文档 与配套脚本 examples/openclaw/main.py 展开,讲解如何把 OpenClaw Gateway 容器化地运行在一个 OpenSandbox 沙箱实例中:通过 Python SDK 创建沙箱、以自定义 entrypoint 启动 Gateway、按 FQDN 白名单收紧出网策略、轮询健康检查直至 Gateway 返回 HTTP 200,最终拿到一个可直接访问的 HTTP 端点。读完本文,你将掌握「沙箱内运行长驻 HTTP 服务 + 端点暴露 + 出网管控」这一 OpenSandbox 典型集成模式的完整流程与底层机制。

场景说明:为什么把 Gateway 放进沙箱

OpenClaw 是一个 Agent Gateway 程序,默认以常驻进程方式监听 HTTP 端口。将它放进 OpenSandbox 沙箱的意义在于:

  • 进程级隔离:Gateway 及其依赖的 Node.js 运行时、模型调用链都运行在一次性沙箱容器内,生命周期由沙箱timeout控制,到期自动回收;
  • 出网最小化:通过NetworkPolicy声明 FQDN 级别的 egress 白名单,沙箱默认拒绝一切出网请求,只放行显式允许的域名;
  • 端点标准化:不直接暴露容器端口,而是通过sandbox.get_endpoint(port)拿到由 OpenSandbox 服务分配的可达地址(宿主机映射端口或经由服务端代理),客户端只需访问该地址即可。

这套模式适用于任何「在沙箱里跑一个带端口的 HTTP 服务」的集成场景,OpenClaw 只是其中的一个具体样例。

快速开始

文档给出的最小运行路径是两步:

# Install dependencies uv pip install opensandbox requests # Run with default settings uv run python examples/openclaw/main.py

前提是本机已经运行了 OpenSandbox server(详见下文 启动 OpenSandbox 服务 一节)。默认配置下,脚本会连接http://localhost:8080的服务端,拉取ghcr.io/openclaw/openclaw:latest镜像创建沙箱,并在 18789 端口上启动 Gateway。

配置项:以源码为准的环境变量

examples/openclaw/main.py 通过环境变量覆盖默认值。结合源码(main.pyL26-L31)可以确认实际读取的全部变量如下:

变量默认值说明
OPEN_SANDBOX_SERVERhttp://localhost:8080OpenSandbox 服务地址
OPEN_SANDBOX_API_KEY空(不鉴权)服务端 API Key
OPENCLAW_IMAGEghcr.io/openclaw/openclaw:latestGateway 容器镜像
OPENCLAW_TIMEOUT3600沙箱生命周期(秒)
OPENCLAW_TOKENdummy-token-for-sandboxGateway 认证 token
OPENCLAW_PORT18789Gateway 监听端口

需要指出的是,文档中的配置表 将服务地址变量写作OPENCLAW_SERVER,但当前main.py源码实际读取的是OPEN_SANDBOX_SERVER,且源码额外支持了文档表中未列出的OPEN_SANDBOX_API_KEYOPENCLAW_PORT。以源码为准可避免配置不生效的问题。

此外,main.pyL71 还会优先读取OPENCLAW_GATEWAY_TOKEN:若显式设置了该变量,则覆盖OPENCLAW_TOKEN的默认值,作为更强的鉴权凭据注入沙箱。

核心脚本解析:SandboxSync.create 的完整参数

examples/openclaw/main.py 的核心调用如下(L80-L101),这里完整保留并逐项展开:

sandbox = SandboxSync.create( image=image, timeout=timedelta(seconds=timeout_seconds), metadata={"example": "openclaw"}, entrypoint=["node", "dist/index.js", "gateway", "--bind=lan", "--port", str(port), "--allow-unconfigured", "--verbose"], connection_config=ConnectionConfigSync(domain=server, api_key=api_key), health_check=lambda sbx: check_openclaw(sbx, port), # env for openclaw env={ "OPENCLAW_GATEWAY_TOKEN": token }, # use network policy to limit openclaw network accesses network_policy=NetworkPolicy( defaultAction="deny", egress=[ NetworkRule(action="allow", target="pypi.org"), NetworkRule(action="allow", target="pypi.python.org"), NetworkRule(action="allow", target="github.com"), NetworkRule(action="allow", target="api.github.com"), ], ), )

对照 SDK 中SandboxSync.create的签名(sdks/sandbox/python/src/opensandbox/sync/sandbox.py),有几个与本文强相关的参数值得展开:

  • entrypoint:覆盖镜像默认启动命令。若不传,SDK 会退化为["tail", "-f", "/dev/null"]sync/sandbox.pyL515),Gateway 根本不会启动。这里传入的是 OpenClaw 的官方 gateway 启动方式:node dist/index.js gateway --bind=lan --port 18789 --allow-unconfigured --verbose

  • timeout:沙箱最大存活时间。示例用timedelta(seconds=3600)控制一小时后回收;SDK 文档注明传None则需要显式清理(sync/sandbox.pyL483)。

  • env:注入沙箱内的环境变量。文档中同时给出了追加OPENCLAW_MODEL的示例,用于指定 Gateway 背后的模型:

    env={ "OPENCLAW_GATEWAY_TOKEN": token, "OPENCLAW_MODEL": "claude-sonnet-4-20250514", # Add more env vars as needed },
  • health_check:自定义同步健康检查函数,取代默认的 ping 检查。示例传入lambda sbx: check_openclaw(sbx, port),把「Gateway 真正可用」作为沙箱 ready 的判据。

  • network_policy:出网策略,见下一节。

出网管控:NetworkPolicy 与 NetworkRule 的底层定义

文档强调:默认情况下沙箱拒绝所有网络访问,仅放行pypi.org(用于安装依赖包),并且可以在main.py中自定义。结合源码,策略模型的定义位于 sdks/sandbox/python/src/opensandbox/models/sandboxes.py:

class NetworkRule(BaseModel): """Egress rule for matching network targets.""" action: Literal["allow", "deny"] target: str # FQDN or wildcard domain (e.g., "example.com", "*.example.com") class NetworkPolicy(BaseModel): """Egress network policy matching the sidecar `/policy` request body.""" default_action: Literal["allow", "deny"] | None = Field( default="deny", alias="defaultAction", ) egress: list[NetworkRule] | None

从模型定义可以确认三点关键事实:

  1. 默认动作是deny——即使不写任何egress规则,未匹配流量也会被拒绝,这是典型的「白名单」姿态;
  2. target支持通配域名,例如*.example.com,可以按域名族整体放行;
  3. 规则按顺序求值egress字段描述为 "evaluated in order"),规则体直接对应 egress sidecar 的/policy请求。

示例中的完整白名单(main.pyL92-L100)在 pypi 之外还放行了github.comapi.github.com,以便 Gateway 在沙箱内完成代码托管相关调用。按需增删NetworkRule条目即可收紧或放宽策略。

健康检查:轮询直到 Gateway 返回 200

check_openclaw(main.py)实现了「就绪 = HTTP 200」的语义:

def check_openclaw(sbx: SandboxSync, port: int = DEFAULT_PORT) -> bool: endpoint = sbx.get_endpoint(port) start = time.perf_counter() url = f"http://{endpoint.endpoint}" for _ in range(150): # max for ~30s try: resp = requests.get(url, timeout=1) if resp.status_code == 200: elapsed = time.perf_counter() - start print(f"[check] sandbox ready after {elapsed:.1f}s") return True except Exception as exc: pass time.sleep(0.2) return False

实现细节:每轮先向 Gateway 根路径发起一次GET(超时 1 秒),每 0.2 秒重试一轮,最多 150 轮,即最多约 30 秒。这与 SDK 侧的机制是衔接的:SandboxSync.create拿到沙箱后,若未设置skip_health_check,会调用sandbox.check_ready(ready_timeout, health_check_polling_interval)(sync/sandbox.py),其中ready_timeout默认 30 秒、轮询间隔默认 200 毫秒(L460、L474),is_healthy会优先执行传入的custom_health_check(L425-L426)。也就是说,create返回时 Gateway 已经通过 HTTP 200 校验,后续代码可以立即安全地取端点。

端点暴露:get_endpoint 的作用

就绪之后,脚本取端点并打印(main.pyL103-L104):

endpoint = sandbox.get_endpoint(port) print(f"Openclaw started finished. Please refer to {endpoint.endpoint}")

get_endpoint的实现在 sync/sandbox.py,它向服务端查询该沙箱上指定端口的映射地址,并根据connection_config.use_server_proxy决定是直连还是走服务端代理。对调用方而言,无论底层是 Docker 端口映射还是代理转发,拿到的都是同一个endpoint.endpoint(形如127.0.0.1:56123的主机端口),无需关心沙箱内部的实际端口。

启动 OpenSandbox 服务(本地 Docker runtime)

服务端默认使用runtime.type = "docker",因此必须能连上一个运行中的 Docker daemon。文档特别给出了两种环境的前置检查:

  • Docker Desktop:确保 Docker Desktop 正在运行,随后用docker version验证;
  • Colima(macOS):先启动colima start,再导出 socket 路径,然后才启动服务端:
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"

随后预拉取 OpenClaw 镜像,避免首次创建沙箱时的拉取等待:

docker pull ghcr.io/openclaw/openclaw:latest

最后安装并启动 OpenSandbox server(日志保留在终端中):

uv pip install opensandbox-server opensandbox-server init-config ~/.sandbox.toml --example docker opensandbox-server

init-config --example docker会生成一份以 Docker 为运行时的示例配置~/.sandbox.toml,可按需修改后由opensandbox-server加载。

创建并访问 OpenClaw 沙箱:完整流程与预期输出

示例脚本硬编码了快速开始参数:

  • OpenSandbox 服务:http://localhost:8080
  • 镜像:ghcr.io/openclaw/openclaw:latest
  • Gateway 端口:18789
  • 超时:3600s
  • Token:环境变量OPENCLAW_GATEWAY_TOKEN(默认dummy-token-for-sandbox

从项目根目录执行:

export OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)" uv run python examples/openclaw/main.py

其中openssl rand -hex 32生成 64 位十六进制随机串作为 Gateway 鉴权 token;如果只是本地体验,不设置该变量时脚本会回落到dummy-token-for-sandbox

运行成功后,输出类似:

Creating openclaw sandbox with image=ghcr.io/openclaw/openclaw:latest on OpenSandbox server http://localhost:8080... [check] sandbox ready after 7.1s Openclaw started finished. Please refer to 127.0.0.1:56123

第一行确认了创建参数;第二行是check_openclaw打印的就绪耗时;第三行的127.0.0.1:56123即为 Gateway 的可达端点,浏览器或curl直接访问即可。

进阶:自定义 Gateway 端口

若不想占用默认的 18789 端口,文档给出的改法是两处联动修改main.py

其一,修改entrypoint中的--port参数:

entrypoint=["node dist/index.js gateway --bind=lan --port 19999 --allow-unconfigured --verbose"],

其二,get_endpoint()调用同步改为新端口:

endpoint = sandbox.get_endpoint(19999)

同时建议把OPENCLAW_PORT环境变量一并设置为19999,保持健康检查函数(默认读取DEFAULT_PORT)与实际监听端口一致。

小结与延伸阅读

本文覆盖的链路可以概括为:SandboxSync.create(entrypoint 启动 Gateway + env 注入 token + NetworkPolicy 收紧出网)→ 自定义health_check轮询 HTTP 200 →get_endpoint获取可达地址。几个值得继续深入的仓库位置:

  • examples/openclaw/main.py:本示例的完整可运行脚本;
  • sdks/sandbox/python/src/opensandbox/sync/sandbox.py:SandboxSynccreate/check_ready/get_endpoint实现;
  • sdks/sandbox/python/src/opensandbox/models/sandboxes.py:NetworkPolicy/NetworkRule数据模型;
  • docs/examples/index.md:OpenSandbox 全部示例索引,OpenClaw 与 Claude Code、Gemini CLI、Playwright 等示例共享同一套「沙箱内跑服务 + 端点暴露」模式,可横向对照。

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询