一文搞懂如何本地搭建OpenHands软件开发代理平台跨设备协作 1. 为什么要在 Linux 上用 Docker 跑 OpenHands 并做内网穿透OpenHands 是一个开源的软件开发代理平台你可以把它理解成一个能自己动手写代码、执行命令、浏览网页的 AI 编程助手。它不只是给你补全几行代码而是能接收一个任务描述然后自主规划步骤、创建文件、运行脚本、调试报错最后把可运行的结果交给你。适合谁用独立开发者、需要快速验证原型的技术团队以及想把重复性编码工作交给代理去跑的人。我自己的使用场景是这样的主力开发机是一台放在家里的 Ubuntu 22.04 小主机平时跑各种容器服务。但人经常在外面用笔记本或者平板的时候想调用这台机器上的 OpenHands 帮我处理一些代码任务。问题就来了——家里的机器在内网外网根本访问不到。传统的做法是买云服务器、配反向代理、搞域名备案成本和维护量都不小。这时候两个工具组合起来就很舒服Docker 负责把 OpenHands 的运行环境封装好一条命令拉起来不用担心依赖冲突cpolar 负责内网穿透把本地 3000 端口的 Web 界面映射到一个公网地址任何设备打开浏览器就能用。整套流程不需要公网 IP不需要云服务器也不需要动路由器。这篇文章我会把完整步骤拆开讲从 Docker 拉镜像、启动容器、配置模型通道到 cpolar 安装、创建隧道、固定二级子域名最后演示从另一台设备打开 Web 界面并跑通一个真实任务。模型 endpoint 部分我会改成 TaoToken 的统一 Key 通道这样你只需要一个 Key 就能切换不同模型不用在多个平台之间来回倒腾。整个流程实测下来从零到能在异地访问大概 15 分钟能搞定。下面开始。2. 前置准备Docker 环境与 TaoToken 统一 Key 通道配置先说环境要求。我用的系统是 Ubuntu 22.04内核 5.15Docker 版本 24.0 以上。如果你还没装 DockerUbuntu 下可以用官方脚本一行搞定curl -fsSL https://get.docker.com | sudo sh sudo systemctl enable --now docker装完后验证一下docker version docker compose version两个命令都能正常输出版本号就说明环境 OK。这里注意OpenHands 的容器需要挂载宿主机的 Docker socket因为它要在内部启动沙箱容器来执行代码。所以你的用户最好在 docker 组里或者直接用 sudo 运行。接下来是模型通道。OpenHands 默认会让你选 LLM 提供商比如 OpenAI、Anthropic 等然后填对应的 API Key。但如果你同时想用多个模型或者想统一管理 Key 和用量逐个平台配置就很麻烦。我的做法是把模型 endpoint 指向 TaoToken 的统一通道一个 Key 走所有模型。TaoToken 的 API 地址是https://taotoken.net/api兼容 OpenAI 的接口格式。你需要在官网注册后拿到 API Key然后在 OpenHands 的设置里这样填LLM Provider 选择OpenAI或CustomBase URL 填https://taotoken.net/apiAPI Key 填你申请到的 KeyModel 填你要用的模型 ID比如claude-sonnet-4-20250514或gpt-4o如果你更习惯用配置文件的方式OpenHands 也支持通过环境变量注入。在启动容器的时候加上-e LLM_API_KEY你的TaoToken Key \ -e LLM_BASE_URLhttps://taotoken.net/api \ -e LLM_MODELclaude-sonnet-4-20250514这样容器一起来就已经配好了模型通道不用在 Web 界面里再手动填一遍。对于需要频繁重建容器的场景这种方式更省事。有一点要提醒TaoToken 的 Key 不要直接硬编码在会提交到 Git 的脚本里。建议用.env文件管理或者通过 shell 的 export 注入。下面我会给出完整的 docker run 命令你可以把 Key 部分替换成自己的。3. 可复制配置docker run 启动 OpenHands 与 cpolar 隧道命令这一节是核心操作部分所有命令都可以直接复制。先拉镜像sudo docker pull docker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik然后启动 OpenHands 容器。下面这条命令我加了模型通道的环境变量端口映射到宿主机的 3000同时挂载了 Docker socketsudo docker run -it --pullalways \ -e SANDBOX_RUNTIME_CONTAINER_IMAGEdocker.all-hands.dev/all-hands-ai/runtime:0.14-nikolaik \ -e LOG_ALL_EVENTStrue \ -e LLM_API_KEY你的TaoToken Key \ -e LLM_BASE_URLhttps://taotoken.net/api \ -e LLM_MODELclaude-sonnet-4-20250514 \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ --add-host host.docker.internal:host-gateway \ --name openhands-app \ docker.all-hands.dev/all-hands-ai/openhands:0.14几个参数解释一下。--add-host host.docker.internal:host-gateway是为了让容器内部能访问宿主机服务某些沙箱操作会用到。-v /var/run/docker.sock是必须的否则 OpenHands 没法启动运行时容器。-p 3000:3000把 Web 界面暴露到宿主机。启动后打开浏览器访问http://localhost:3000应该能看到 OpenHands 的界面。首次进入会弹设置窗口如果你已经用环境变量配好了模型这里可以直接跳过或者确认一下。接下来装 cpolar。一键脚本sudo curl https://get.cpolar.sh | sh装完检查服务状态sudo systemctl status cpolar看到active (running)就正常。然后浏览器打开http://localhost:9200进入 cpolar 管理界面用注册的账号登录。登录后创建隧道。点击左侧「隧道管理」→「创建隧道」填写隧道名称openhands不要和已有隧道重名协议http本地地址3000域名类型随机域名地区China Top创建成功后在「在线隧道列表」里能看到两个公网地址http 和 https 各一个。复制 https 那个地址在任意设备的浏览器打开就能看到 OpenHands 界面了。如果你想要固定地址不让它 24 小时变一次需要配置二级子域名。先去 cpolar 官网左侧「预留」→「保留二级子域名」地区选china vip设置一个名字比如myopenhands点击保留。然后回到 cpolar Web 界面编辑刚才的隧道域名类型二级子域名Sub Domain填你保留的名字地区China VIP更新后在线隧道列表里的地址就变成固定的了比如https://myopenhands.cpolar.cn。这个地址不会变适合长期使用。4. 验证请求从另一台设备打开 Web 界面并跑通任务配置完成后必须验证。我拿一台笔记本连手机热点模拟异地环境打开 cpolar 给的 https 地址。页面加载出来后先确认模型通道是否生效。在 OpenHands 界面里点齿轮图标进设置检查 Base URL 是不是https://taotoken.net/apiModel 是不是你填的那个。如果环境变量没生效这里手动补一下也行。然后输入一个测试任务比如请编写一个 bash 脚本 hello.sh打印 hello world!然后运行它并输出结果。点发送后OpenHands 会在左侧显示任务描述右侧逐步展示它的思考和操作。你会看到它创建文件、写入内容、执行脚本最后在对话框里输出hello world!。这说明模型通道和沙箱都正常工作。再试一个稍微复杂点的用 HTML 和 JavaScript 创建一个简单的计算器支持加减乘除然后启动一个本地服务器让我预览。OpenHands 会生成index.html然后启动一个 HTTP 服务并在对话框里给出访问链接。你可以在另一台设备上直接打开这个链接验证计算器是否可用。我实测下来从发送任务到拿到可预览的链接大概 30 秒左右取决于模型响应速度。这里有个细节如果你在异地设备上访问 cpolar 地址时提示需要登录那是因为 cpolar 免费版对新域名有登录要求。重新登录一下 cpolar 账号即可不影响 OpenHands 本身的使用。验证通过后你就有了一套完整的跨设备协作环境家里的 Linux 机器跑 OpenHands任何设备通过 cpolar 地址访问模型走 TaoToken 统一通道。接下来不管是在咖啡馆用平板改代码还是在公司用笔记本跑任务都不需要重新配置环境。5. 本篇常见错排查401、local proxy failed、reading choices 等报错这一节列几个我踩过的坑和对应的解决办法。报错一401 Unauthorized这是最常见的。原因通常是 API Key 填错、过期或者 Base URL 写成了https://taotoken.net而漏了/api。检查两处OpenHands 设置里的 Base URL 必须是https://taotoken.net/apiKey 必须是完整的字符串前后不要有空格。如果你用的是环境变量注入进容器里echo $LLM_API_KEY确认一下有没有被 shell 转义。报错二local proxy failed / connection refused这个通常出现在容器启动阶段OpenHands 尝试连接模型 endpoint 但网络不通。先确认宿主机能访问https://taotoken.net/apicurl -I https://taotoken.net/api如果宿主机通但容器不通检查 docker run 命令里有没有加--add-host host.docker.internal:host-gateway。另外如果你之前配过系统级代理容器内可能继承了代理设置导致连接失败可以在 docker run 里加-e NO_PROXYtaotoken.net排除。报错三Error reading choices / unexpected response format这个报错说明模型返回的数据格式和 OpenHands 预期的不一致。常见原因是 Model ID 填错了比如填了一个 TaoToken 通道不支持的模型名。解决办法是去 TaoToken 的模型列表确认可用模型 ID然后填准确。另外如果你在设置里同时填了 OpenAI 官方 Key 和 TaoToken 的 Base URL也会出现这种混乱确保 Key 和 Base URL 是配套的。报错四OAuth / 登录循环cpolar 免费版对新域名有登录要求异地访问时可能反复跳登录页。解决办法有两个一是升级 cpolar 套餐解除限制二是配置固定的二级子域名登录一次后 cookie 能保持更久。如果你用的是随机域名每次地址变化都要重新登录体验确实一般。报错五容器启动后 3000 端口访问不了先docker ps看容器是不是在运行。如果容器频繁重启docker logs openhands-app看日志。常见原因是 Docker socket 权限不够或者宿主机 3000 端口被占用。换一个端口映射比如-p 3001:3000试试。排查的时候记住一个原则先确认宿主机到 TaoToken 的连通性再确认容器到宿主机的连通性最后确认 cpolar 隧道是否正常转发。三层都通了问题基本就定位到了。6. 长期使用建议与统一 Key 通道的接入入口如果你只是偶尔用一下随机域名 免费版 cpolar 就够了。但如果打算长期把 OpenHands 当成日常开发代理来用建议做两件事一是配置固定的二级子域名避免地址变化导致的书签失效和重复登录二是把模型通道统一到 TaoToken这样切换模型不用改代码只改一个 Model ID 就行。对于需要长期跑编码任务或者 Agent 工作流的场景TaoToken 的 Coding Plan 更适合用量和并发都有保障。你可以在这里了解详情模型对话入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodel_chatCoding Plan 入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcoding_planAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapi_keys接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc最后分享一个实用技巧OpenHands 的容器重建后之前的会话记录会丢失。如果你需要保留历史任务可以把容器内的/app/workspace目录挂载到宿主机-v /home/yourname/openhands-workspace:/app/workspace这样即使容器删了重建工作区和历史文件还在。配合固定的 cpolar 地址和 TaoToken 统一 Key整套环境就非常稳定了随时随地从任何设备接入不用再折腾配置。