在 VPS 上自托管 OpenHands
OpenHands 是一个会编写并运行代码的 AI 智能体,因此部署时需格外小心。请用 Docker 把它安装在 VPS 上,并锁定 Web 界面及其密钥。
OpenHands 是什么,以及首先要理解的那一个风险
OpenHands 的前身是 OpenDevin,是一个能够自主完成软件工程工作的 AI 智能体(agent)。您用自然语言给它一个任务,它便会规划工作、编写代码、运行命令、读取输出,并不断迭代直到任务完成。您在自己的服务器上用 Docker 运行它,并把它接入一个语言模型。放在 VPS 上,它就成了一个在您离开时仍能持续工作的编码智能体。
有一个事实应当贯穿您整个部署过程。OpenHands 不只是给出代码建议,它还会真正运行代码;为了做到这一点,它的控制器容器会把宿主机的 Docker 套接字挂载到 /var/run/docker.sock,以便为每个任务启动沙箱容器。任何能与 Docker 套接字通信的东西,都能启动一个把您整个宿主机文件系统挂载进去的新容器,这意味着套接字访问权限实际上等同于这台机器上的 root 权限。所以请把这台 OpenHands 机器当作一台运行不受信任代码的服务器来对待,因为它做的正是这件事。下面每一项加固措施都由此而来。
您需要准备什么
您需要一台运行 Ubuntu 24.04 的 VPS,安装较新版本的 Docker Engine,至少 4 GB 内存,以及一个语言模型的 API 密钥(OpenAI、Anthropic 或 Google),或者由 同一台 VPS 上的 Ollama 提供的本地模型。OpenHands 支持数十种模型后端,选择权在您。如果您以前从未搭建过容器,VPS 上 Docker 的基础知识 涵盖了本文所默认您已掌握的内容。
用 Docker 安装
OpenHands 以两个镜像的形式发布:您运行的应用镜像,以及它拉取来为每个任务运行沙箱的 agent-server 镜像。像下面这样运行它,并把项目文档中的当前标签替换进去:
docker run -it --rm --pull=always \
-e AGENT_SERVER_IMAGE_REPOSITORY=ghcr.io/openhands/agent-server \
-e AGENT_SERVER_IMAGE_TAG=1.26.0-python \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands:/.openhands \
-p 127.0.0.1:3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands \
docker.openhands.dev/openhands/openhands:1.8有两个细节能帮您省下一小时的困惑。应用镜像和 agent-server 镜像的版本号是有意不同的,所以请不要试图让它们保持一致:请使用文档中与您的应用版本相配套的 agent-server 标签。另外请注意这里用的是 -p 127.0.0.1:3000:3000,而不是 -p 3000:3000。这一处小小的改动,决定了 Web 界面究竟是只有您能访问,还是整个互联网都能访问,而下一节讲的正是这件事。
让 Web 界面远离公网
OpenHands 在 3000 端口上提供它的界面。这个界面驱动着一个会运行代码的智能体,所以把它发布到互联网上,就等于把一条通往执行命令进程的远程通道,交给了任何发现它的人。请像上面的运行命令那样把它绑定到回环地址,然后从您的笔记本电脑通过 SSH 隧道访问它:
ssh -L 3000:127.0.0.1:3000 you@your-vps然后在您自己的机器上打开 http://127.0.0.1:3000。流量走的是您已有的 SSH 会话,公网上不会有任何新的监听端口。如果需要更长期的方案,可以改为把它放在 VPN 之后。无论哪种方式,都请在这台机器前面放一道默认拒绝的防火墙,以免有东西被意外暴露;并且请记住,只覆盖 IPv4 的防火墙会让同一个端口在 IPv6 上仍然敞开,这正是坑了很多人的 IPv6 防火墙缺口。
隔离模型密钥和任何仓库凭据
OpenHands 需要一个模型的 API 密钥,往往还需要一个用于克隆和推送到您仓库的令牌。两者都能花钱,也都能以您的身份行事,所以请把它们当作密码来对待。请把它们放在一个只有对应账户才能读取的环境文件中,绝不要写进运行命令里(那样会落进您的 shell 历史和进程列表),也绝不要放进 git 仓库内的文件里。
把它跑在一台可以随时丢弃的机器上
因为控制器必须持有 Docker 套接字,您无法把 OpenHands 与其宿主机完全隔离开。诚实的缓解办法是通过部署位置来隔离:把 OpenHands 跑在一台专用的 VPS 上,这台机器上不放任何您在意的其他东西,而不是跑在同时运行着您的数据库或网站的服务器上。开始前先做一个快照,之后宁可从该快照重建,也不要信任一台已经运行了一周智能体所写代码的机器。一台便宜、可丢弃、单一用途的 VPS 才是它合适的归宿。
为它周围的机器做加固
其余的都是标准的服务器卫生工作,而在这里它比平时更重要,因为这里的工作负载比平时更危险。请创建一个非特权的管理员用户,而不是以 root 身份工作,参见 以非特权用户身份运行服务。把 SSH 改为仅密钥认证。然后照着下面的清单逐项检查,并把它放在您日后还会再看到的地方。
如果您想真正理解各个组成部分,而不只是照着跑,请看 在 VPS 上构建您自己的 AI 智能体;如果想要一个更少代码的平台,自托管 Dify 是一个更平缓的入门途径。
FAQ
在服务器上运行 OpenHands 安全吗?
小心操作的话可以做到安全,但它比普通的 Web 应用风险更高,因为它会编写并运行代码,而且它的控制器持有宿主机的 Docker 套接字,这实际上等同于机器上的 root 权限。请把它跑在一台专用、可丢弃、不放任何其他重要东西的 VPS 上,让它的 Web 界面留在回环地址上并置于 SSH 隧道或 VPN 之后,隔离它的密钥,并对这台机器做加固。不要把它跑在您的重要服务旁边。
OpenHands 为什么需要 Docker 套接字?
OpenHands 会在一个全新的沙箱容器里运行每个任务,而它是通过把 /var/run/docker.sock 挂载进控制器、请求宿主机的 Docker 守护进程来创建这些容器的。这就让控制器容器拥有了对宿主机上 Docker 的控制权,既强大又危险,所以宿主机本身必须被当作一台运行不受信任代码的机器来对待。
OpenHands 能用本地模型代替付费 API 吗?
可以。OpenHands 支持由 Ollama 或 vLLM 提供的本地模型,所以您可以完全自托管地运行它,既没有按 token 计费的成本,也不会有数据离开您的服务器。您需要一台内存足够运行一个有能力的编码模型的机器,这与 Ollama 指南中所讲的正是同一个规格问题。
我应该把 OpenHands 跑在我的主服务器上吗?
不应该。因为它会运行智能体所写的代码并持有 Docker 套接字,请把它放在一台单独、单一用途、您愿意随时重建的 VPS 上。把它和数据库、网站或您的其他服务放在一起,意味着智能体的一次失误,或它自身的一个缺陷,就可能触及它本不该触及的东西。