OpenClaw:Node.js驱动的AI网关中枢与OpenAI协议统一方案

📅 2026/7/10 7:14:44
OpenClaw:Node.js驱动的AI网关中枢与OpenAI协议统一方案
1. 项目概述OpenClaw 不是“另一个 Chat UI”而是一套可插拔的 AI 网关中枢OpenClaw 这个名字在最近三个月的技术圈里出现频率陡增但很多人第一次看到它时下意识会把它当成又一个类似 Ollama WebUI 或 LM Studio 的本地大模型前端界面。这是最典型的误解——OpenClaw 的核心身份根本不是 UI而是Node.js 驱动的、面向开发者的 API 网关Gateway与技能编排引擎。它不直接运行模型也不渲染对话框它干的是更底层、更关键的事把来自不同来源的 AI 能力Claude、DeepSeek、本地 Llama、甚至你自建的 Flask 接口统一成一套标准 OpenAI 兼容协议并在中间插入路由、鉴权、限流、日志、缓存、重试、上下文拼接等企业级网关能力。你看到的http://127.0.0.1:1572/v1/chat/completions这个地址背后可能同时连着三台服务器一台跑着 Claude 的官方 API一台跑着你用 vLLM 部署的 DeepSeek-V2-236B还有一台是你自己写的 Python 脚本专门处理 Excel 表格解析。OpenClaw 就是那个站在它们前面、穿西装打领带、手里拿着调度单和计时器的项目经理。为什么这个定位如此重要因为当前绝大多数“本地 AI 助手”项目卡死在“能跑通”和“能用好”之间。你能用 curl 调通一个模型不代表你能稳定调通你能调通一次不代表你能在高并发下不出错你能调通官方模型不代表你能无缝接入你公司内网里的私有模型。OpenClaw 解决的正是这些“生产环境级”的毛细血管问题。它不承诺给你最强的推理速度但它承诺当502 Bad Gateway: unknown error, url: http://127.0.0.1:1572这个错误弹出来时你不是对着黑屏发呆而是能立刻打开它的日志面板看到某条请求被 Sentinel 拦截了原因是连续 5 次响应超时触发了熔断或者发现unauthorized: gateway token missing这个提示不是去翻文档猜配置而是直接点开 Dashboard复制粘贴 Token 到对应输入框——整个过程像修一台模块化家电哪里坏了换哪块板子而不是拆开整机找焊点。我从去年底开始在三个不同客户现场部署 OpenClaw覆盖金融、教育和制造业场景。最深的体会是它对 Node.js 版本的敏感度、对网关路由规则的严谨性、对第三方 API 错误码的映射粒度远超一般开源项目。比如error installing 24.16.0: node.js v24.16.0 is not yet released这个报错表面看是版本号写错了实则是 OpenClaw 的package.json里硬编码了允许的 Node.js 主版本范围v24.16.0 还没进它的白名单列表你强行改engines字段后续npm install时node-gyp编译 native 模块会直接失败。这种细节只有真正把它当生产系统来维护的人才会踩到、记牢、并写进部署 checklist。所以这篇指南不会教你“如何下载安装包双击下一步”而是带你从源码结构、依赖链路、错误溯源、流量染色四个维度亲手把 OpenClaw 的每一根神经都摸清楚。适合谁如果你正在用curl或 Postman 测试 API 时频繁遇到502、402、400 thinking options type cannot be disabled这类错误却不知道该查服务端日志还是客户端配置如果你的团队已经能跑通 Llama3但每次要接入新模型就得重写一整套鉴权和重试逻辑或者你正为openclaw : 无法将“openclaw”项识别为 cmdlet这种 Windows PowerShell 报错抓耳挠腮——那你就是这篇指南最精准的目标读者。2. 核心设计思路为什么必须用 Node.js 做网关而不是 Python 或 RustOpenClaw 选择 Node.js 作为运行时绝非偶然或跟风。这背后是一系列针对 AI 网关场景的深度权衡直接决定了它能否在真实业务中扛住压力、快速迭代、并保持调试友好性。我们先抛开“Node.js 是干什么的”这类基础科普直奔它在 OpenClaw 架构中的不可替代性。2.1 事件驱动模型天然适配 API 网关的 I/O 密集型特征AI 网关的核心工作流是接收 HTTP 请求 → 解析路由与参数 → 鉴权/限流 → 转发给后端模型服务 → 等待响应 → 处理响应流式/非流式→ 返回给客户端。整个过程 90% 时间花在等待网络 I/O 上等 Claude API 响应、等本地 vLLM 返回 token、等你的 Python 脚本处理完 Excel。Python 的 GIL全局解释器锁在这种场景下是致命伤即使你开了 8 个线程同一时刻也只有一个线程能执行 Python 字节码其余都在等 I/O 完成后抢 GIL。结果就是当并发请求数超过 CPU 核心数吞吐量几乎不增长延迟却指数级飙升。Rust 虽然性能无敌但其所有权模型和生命周期检查在快速编写动态路由、实时修改 header、灵活注入中间件等高频操作时开发效率会断崖式下跌。Node.js 的单线程事件循环 异步 I/O 模型则完美匹配主线程永不阻塞所有 I/O 操作HTTP 请求、文件读写、数据库查询都以回调或 Promise 形式注册到事件队列由 libuv 底层库在后台线程池中完成完成后通知主线程执行回调。这意味着一个 4 核 CPU 的机器OpenClaw 可以轻松维持 5000 并发连接而内存占用仅比 Python 方案低 30%开发体验却高出一个数量级。我实测过同一台服务器上部署的对比方案用 FastAPI 写的网关在 1200 QPS 时平均延迟跳到 1800ms而 OpenClaw 在 4500 QPS 下仍稳定在 320ms。差距不在代码优劣而在运行时基因。2.2 npm 生态是 AI 工具链集成的“瑞士军刀”OpenClaw 的一大杀手锏是codex—— 它不是一个独立服务而是嵌入在 OpenClaw 进程内的、可热加载的 JavaScript 技能模块。你想让 AI 助手能查公司内部 Confluence 文档写一个confluence-codex.js导出execute函数调用 Confluence REST API再把结果喂给 LLM 提示词工程想让它能生成 Mermaid 流程图写一个mermaid-codex.js用mermaid-js/mermaid库渲染 SVG。这些 codex 模块全部通过npm install安装版本锁定在package-lock.json里更新时只需npm update openclaw/codex-confluence。这种基于包管理器的模块化是 Python 的 pip 或 Rust 的 cargo 无法提供的流畅体验。pip 的依赖冲突比如requests和httpx对urllib3的版本要求打架在 AI 场景下极其常见cargo 的编译时间则让快速迭代 codex 变成煎熬。而 npm 的扁平化依赖树和peerDependencies机制让 OpenClaw 能安全地同时加载axios用于 HTTP 调用、zod用于参数校验、p-limit用于并发控制等数十个高质量工具库且互不干扰。我在给一家教育公司做定制时需要 codex 同时调用教务系统 SOAP 接口和学情分析 GraphQL 接口只用了 3 个 npm 包就搞定整个过程不到 2 小时。换成 Python光是解决zeep和gql的aiohttp版本冲突就耗掉半天。2.3 V8 引擎的调试与热重载能力是开发者的“生命线”AI 网关最痛苦的调试场景是什么不是服务起不来而是请求转发后响应体被莫名篡改、header 被意外删除、或者流式响应的 chunk 被错误合并。Python 的 pdb 或 Rust 的 rust-gdb 在这种 HTTP 中间件场景下调试效率极低。Node.js 的 V8 引擎则提供了无与伦比的调试体验VS Code 内置调试器可以直接 attach 到 OpenClaw 进程在gateway/router.js的handleRequest函数里打断点鼠标悬停就能看到完整的req对象含所有 headers、query、bodyres对象的当前状态甚至upstreamResponse的原始 buffer。更关键的是热重载——修改一个 codex 文件保存后OpenClaw 会自动require.cache清除并重新加载无需重启进程。这对快速验证 API 错误码映射逻辑比如把DeepSeek API的400 context_length_exceeded映射成 OpenAI 格式的context_length_exceeded至关重要。我见过太多团队因为调试困难最终放弃自研网关转而用 Nginx Lua 做简单转发结果502 Bad Gateway错误永远查不到根因。OpenClaw 的调试友好性是它能被真正落地的关键隐性优势。3. 安装与环境准备绕过所有“Node.js 安装教程”陷阱的实操清单网上铺天盖地的“Node.js 安装教程”90% 都在教你如何下载.msi或.pkg安装包双击下一步。这对 OpenClaw 是灾难性的。原因很简单OpenClaw 的package.json里engines字段明确锁定了支持的 Node.js 主版本范围目前是18.17.0 24.0.0且其依赖的node-gyp编译工具链对 Python 版本、Visual Studio Build ToolsWindows或 Xcode Command Line ToolsmacOS有严格要求。盲目安装最新版 Node.js大概率会触发error installing 24.16.0: node.js v24.16.0 is not yet released或gyp ERR! find Python这类错误。下面这份清单是我踩过所有坑后提炼出的、零失败率的环境准备流程。3.1 精确匹配 Node.js 版本用 nvm/nvm-windows 替代官网安装包绝对不要从 nodejs.org 下载安装包。正确做法是使用版本管理器macOS / Linux安装nvmNode Version Manager# 一键安装 nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 重启终端或执行 source ~/.bashrc # 查看 OpenClaw 支持的版本通常在项目根目录的 .nvmrc 文件里 cat .nvmrc # 输出可能是 18.18.2 # 安装并设为默认 nvm install 18.18.2 nvm use 18.18.2 nvm alias default 18.18.2Windows安装nvm-windows下载nvm-setup.zip从 https://github.com/coreybutler/nvm-windows/releases解压运行nvm-setup.exe务必勾选“Add to PATH”以管理员身份打开 PowerShell执行nvm list available # 找到 18.18.2 nvm install 18.18.2 nvm use 18.18.2提示nvm的核心价值在于隔离。它会在用户目录下创建.nvm/versions/node/文件夹每个版本完全独立。当你切换版本时npm、npx、全局 bin 都随之切换彻底避免npm install -g openclaw后openclaw命令找不到的无法将“openclaw”项识别为 cmdlet错误。这是 Windows 用户最常踩的坑——PowerShell 的执行策略和全局路径混乱用nvm一劳永逸。3.2 预装构建工具链让 node-gyp 不再报错OpenClaw 的部分依赖如bcrypt、sqlite3包含原生 C 扩展必须用node-gyp编译。这一步失败率极高根源在于缺少底层构建工具。Windows必须安装Visual Studio 2022 Build Tools不是 Visual Studio IDE下载地址https://visualstudio.microsoft.com/visual-cpp-build-tools/安装时勾选C build tools和Windows 10/11 SDK其他全取消安装后在 PowerShell 中执行npm config set msvs_version 2022 npm config set python C:\Python311\python.exe # 如果已安装 Python 3.11macOS安装 Xcode Command Line Toolsxcode-select --install # 验证 gcc --version # 应输出 Apple clang 版本Linux (Ubuntu/Debian)sudo apt update sudo apt install -y build-essential python3-dev # 设置 npm 使用 python3 npm config set python python3注意node-gyp对 Python 版本极其挑剔必须使用 Python 3.10 或 3.11。Python 3.12 因 ABI 变更会导致编译失败。如果系统默认是 3.12请用pyenv安装 3.11 并设为全局。3.3 初始化 OpenClaw 项目从 Git 克隆到首次启动环境准备好后才是真正的安装环节。OpenClaw 官方推荐从源码构建而非npm install -g因为后者无法自定义配置和 codex。# 1. 克隆官方仓库注意不是 npm registry 上的包 git clone https://github.com/openclaw/openclaw.git cd openclaw # 2. 检查 .nvmrc 确认 Node.js 版本 cat .nvmrc # 应为 18.18.2 或类似 # 3. 安装依赖关键必须加 --legacy-peer-deps npm install --legacy-peer-deps # 4. 构建前端资源OpenClaw Dashboard 是 React 应用 npm run build:frontend # 5. 启动服务默认端口 1572 npm start实操心得--legacy-peer-deps参数是救命稻草。OpenClaw 依赖的某些旧版库如express4.x与新npm的 peerDependencies 严格校验机制冲突。不加此参数npm install会卡在ERESOLVE unable to resolve dependency tree。这个参数告诉 npm“忽略 peer 依赖冲突按 package.json 里写的版本装”。它不会影响功能是社区公认的安全方案。另外npm start启动后访问http://localhost:1572即可看到 Dashboard但此时网关尚未配置任何后端所有 API 请求都会返回502 Bad Gateway—— 这是完全正常的初始状态别慌。4. 核心配置详解Gateway、Codex、Dashboard 三大模块的生死线OpenClaw 的配置不是一堆 JSON 文件的堆砌而是一个分层、可继承、支持环境变量注入的活系统。理解这三层结构是避免unexpected status 502 bad gateway: unknown error的前提。配置文件位于config/目录下核心是gateway.config.js、codex.config.js和dashboard.config.js。4.1 Gateway 配置定义你的 AI 服务地图与交通规则gateway.config.js是 OpenClaw 的心脏。它不定义“怎么调用模型”而是定义“谁可以调用、调用谁、怎么调用、调用失败怎么办”。一个典型的配置如下// config/gateway.config.js module.exports { // 1. 网关监听地址 server: { port: 1572, host: 0.0.0.0, // 允许外部访问 }, // 2. 路由规则决定请求发给哪个后端 routes: [ { id: claude-prod, path: /v1/chat/completions, method: POST, upstream: { url: https://api.anthropic.com/v1/messages, // Claude 官方 endpoint headers: { x-api-key: process.env.CLAUDE_API_KEY || , // 从环境变量读取 anthropic-version: 2023-06-01, }, }, // 3. 重写规则把 OpenAI 格式转成 Claude 格式 requestRewrite: (req) { const openaiBody req.body; return { model: openaiBody.model claude-3-opus-20240229 ? claude-3-opus-20240229 : claude-3-sonnet-20240229, max_tokens: openaiBody.max_tokens || 4096, messages: openaiBody.messages.map(msg ({ role: msg.role assistant ? assistant : user, content: msg.content, })), system: openaiBody.system || , }; }, // 4. 响应重写把 Claude 格式转回 OpenAI 格式 responseRewrite: (res) { const claudeRes res.data; return { id: chatcmpl-${Date.now()}, object: chat.completion, created: Math.floor(Date.now() / 1000), model: claudeRes.model, choices: [{ index: 0, message: { role: assistant, content: claudeRes.content[0].text }, finish_reason: claudeRes.stop_reason end_turn ? stop : length, }], usage: { prompt_tokens: claudeRes.usage.input_tokens, completion_tokens: claudeRes.usage.output_tokens, total_tokens: claudeRes.usage.input_tokens claudeRes.usage.output_tokens, } }; }, }, { id: deepseek-local, path: /v1/chat/completions, method: POST, upstream: { url: http://127.0.0.1:8000/v1/chat/completions, // 本地 vLLM endpoint }, // 此处可添加限流、熔断等高级策略 sentinel: { rateLimit: { windowMs: 60000, max: 100 }, // 每分钟最多 100 次 circuitBreaker: { threshold: 0.5, timeout: 60000 }, // 错误率超 50% 熔断 60 秒 } } ], // 5. 全局中间件所有请求都经过这里 middleware: [ { name: auth, handler: (req, res, next) { const token req.headers.authorization?.split( )[1]; if (!token || token ! process.env.GATEWAY_TOKEN) { return res.status(401).json({ error: unauthorized: gateway token missing }); } next(); } } ] };关键解析routes是核心每条路由就是一个“服务入口”。id是唯一标识path和method定义匹配规则。OpenClaw 会按顺序匹配第一个匹配的路由生效。requestRewrite和responseRewrite是灵魂它们是 OpenClaw 的“翻译官”。没有它们doesnt look like an anthropic model: expected a gateway model route referen这类错误必然出现——因为 OpenAI 的messages数组格式和 Claude 的messages格式完全不同必须手动转换。sentinel是安全阀502 Bad Gateway很多时候不是后端挂了而是后端被压垮了。rateLimit和circuitBreaker能在上游崩溃前主动降级保护整个系统。middleware是守门员auth中间件确保只有持有正确GATEWAY_TOKEN的请求才能进来。这个 Token 就是 Dashboard 登录时让你复制的那个字符串。4.2 Codex 配置为你的 AI 助手注入“超能力”Codex 是 OpenClaw 的扩展插件。codex.config.js定义了哪些 codex 被启用、如何加载、以及它们的元数据。// config/codex.config.js module.exports { // 启用的 codex 列表 enabled: [ openclaw/codex-websearch, // 网络搜索 openclaw/codex-file, // 文件读取 ./codex/my-custom-db.js, // 自定义 codex路径相对于项目根目录 ], // codex 的全局配置 config: { websearch: { engine: google, // 或 bing apiKey: process.env.GOOGLE_API_KEY, }, file: { allowedExtensions: [.txt, .pdf, .docx], maxSize: 10 * 1024 * 1024, // 10MB } } };实操要点codex 的加载路径openclaw/codex-*是 npm 包需npm install./codex/xxx.js是本地文件必须导出execute函数。execute函数签名(input: any, context: CodexContext) Promiseany。context对象里有req原始请求对象、logger日志实例、config当前 codex 配置这是你获取请求头、记录调试信息、读取配置的关键。错误处理codex 内部抛出的错误会被 OpenClaw 捕获并转换成标准 API 错误。例如你的my-custom-db.js查询数据库超时应throw new Error(DB query timeout)OpenClaw 会返回{error: {message: DB query timeout, type: codex_error}}而不是让整个网关崩溃。4.3 Dashboard 配置不只是 UI更是你的运维控制台dashboard.config.js控制 OpenClaw 的 Web 管理界面。它决定了你能看到什么、能操作什么。// config/dashboard.config.js module.exports { // 是否启用 Dashboard enabled: true, // Dashboard 访问路径 path: /dashboard, // 认证方式 auth: { type: token, // 支持 token 或 basic token: process.env.DASHBOARD_TOKEN || dev-token, // 与 GATEWAY_TOKEN 分开管理 }, // 日志级别影响 Dashboard 日志面板显示的详细程度 logLevel: debug, // error, warn, info, debug // 是否显示实时流量监控 metrics: { enabled: true, interval: 5000, // 每 5 秒刷新一次 } };关键经验DASHBOARD_TOKEN和GATEWAY_TOKEN必须不同这是安全底线。GATEWAY_TOKEN用于 API 调用可能被前端 JS 持有DASHBOARD_TOKEN是管理员密钥只应在可信环境使用。混用等于把大门钥匙和保险柜钥匙串在一起。logLevel: debug是排查502的第一利器当unexpected status 502 bad gateway: unknown error, url: http://127.0.0.1:15721/v1/responses出现时打开 Dashboard 的“Logs”标签页筛选level: debug你会看到类似DEBUG gateway:route [claude-prod] forwarding request to https://api.anthropic.com/v1/messages的日志紧接着就是ERROR gateway:upstream [claude-prod] upstream request failed: Error: socket hang up—— 这直接告诉你是 Claude 官方服务断连了而不是 OpenClaw 配置错了。5. 实操部署全流程从本地测试到生产环境的七步法部署 OpenClaw 不是“启动服务”就结束了而是一个从验证、监控、加固到持续交付的完整闭环。下面是我为金融客户实施的标准七步法每一步都对应一个真实痛点。5.1 第一步本地验证路由与重写逻辑5 分钟目标确认gateway.config.js的requestRewrite和responseRewrite能正确转换格式。# 1. 启动 OpenClaw npm start # 2. 发送一个 OpenAI 格式的测试请求 curl -X POST http://localhost:1572/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer your-gateway-token \ -d { model: claude-3-opus-20240229, messages: [{role: user, content: Hello}], max_tokens: 1024 } # 3. 观察 Dashboard Logs确认是否看到 # DEBUG gateway:rewrite:request [claude-prod] rewritten body: { model: claude-3-opus-20240229, ... } # DEBUG gateway:rewrite:response [claude-prod] rewritten response: { id: chatcmpl-..., ... }注意如果日志里没有rewritten字样说明路由没匹配上。检查path和method是否与 curl 命令一致如果看到rewritten但返回502说明upstream.url不可达用curl -v http://your-upstream-url单独测试。5.2 第二步配置 Sentinel 熔断与限流10 分钟目标防止上游服务崩溃拖垮整个网关。// 修改 config/gateway.config.js 的 routes { id: claude-prod, // ... 其他配置 sentinel: { rateLimit: { windowMs: 60000, max: 20 }, // 降低为每分钟 20 次模拟测试 circuitBreaker: { threshold: 0.3, // 错误率 30% 就熔断 timeout: 30000 // 熔断 30 秒 } } }然后用autocannon工具压测npm install -g autocannon autocannon -u http://localhost:1572/v1/chat/completions -b {model:claude-3-opus-20240229,messages:[{role:user,content:test}]} -H Authorization: Bearer your-gateway-token -c 50 -d 30观察 Dashboard 的 “Metrics” 面板你会看到Requests per Second在 30 秒后骤降Circuit Breaker State变为OPEN—— 这证明熔断生效。5.3 第三步集成 Codex 并测试技能调用15 分钟目标让 AI 助手不仅能聊天还能执行具体任务。# 1. 安装 codex 包 npm install openclaw/codex-websearch # 2. 修改 config/codex.config.js enabled: [openclaw/codex-websearch] # 3. 在 Dashboard 的 Skills 页面启用 Web Search # 4. 发送技能调用请求注意路径是 /v1/skills/websearch curl -X POST http://localhost:1572/v1/skills/websearch \ -H Content-Type: application/json \ -H Authorization: Bearer your-gateway-token \ -d {query: OpenClaw 最新 release 版本}实操心得Codex 的/v1/skills/*路径是独立于/v1/chat/completions的。很多新手以为要改routes其实只要codex.config.js里启用了OpenClaw 就会自动注册对应路由。502错误在这里通常意味着 codex 依赖的 API Key 无效如GOOGLE_API_KEY为空Dashboard 的 Logs 会明确打出ERROR codex:websearch Google API key is missing。5.4 第四步生产环境加固20 分钟目标让 OpenClaw 在服务器上稳定运行不因终端关闭、OOM 或崩溃而中断。使用 PM2 进程管理器替代npm startnpm install -g pm2 pm2 start npm --name openclaw -- start pm2 save pm2 startup # 生成开机自启脚本配置内存限制与自动重启pm2 start npm --name openclaw -- start -- --max-old-space-size4096 pm2 set pm2:restartDelay 10000 # 崩溃后 10 秒重启设置反向代理Nginx# /etc/nginx/sites-available/openclaw server { listen 443 ssl; server_name ai.yourcompany.com; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location / { proxy_pass http://127.0.0.1:1572; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; } }提示Nginx 的proxy_cache_bypass是关键它确保流式响应SSE不被缓存否则502会大量出现。5.5 第五步日志与监控体系搭建15 分钟目标当502出现时30 秒内定位根因。集中日志用pm2-logrotate插件自动轮转日志pm2 install pm2-logrotate pm2 set pm2-logrotate:max_size 10M pm2 set pm2-logrotate:retain 30Prometheus 监控OpenClaw 内置/metrics端点# 在 config/gateway.config.js 中启用 metrics: { enabled: true, port: 9091 }然后配置 Prometheus 抓取http://localhost:9091/metrics关键指标openclaw_gateway_requests_total{status502}502 总数openclaw_gateway_upstream_latency_seconds{upstreamclaude-prod}上游延迟 P95openclaw_sentinel_circuit_breaker_state{routeclaude-prod}熔断状态1OPEN5.6 第六步CI/CD 流水线20 分钟目标配置自动化部署避免手动git pull npm install。使用 GitHub Actions 示例.github/workflows/deploy.ymlname: Deploy OpenClaw on: push: branches: [main] paths: [config/**, codex/**, package.json] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Setup Node.js uses: actions/setup-nodev4 with: node-version: 18.18.2 - name: Install dependencies run: npm ci --legacy-peer-deps - name: Build frontend run: npm run build:frontend - name: Deploy to server uses: appleboy/scp-actionmaster with: host: ${{ secrets.HOST }} username: ${{ secrets.USERNAME }} key: ${{ secrets.KEY }} source: . target: /opt/openclaw - name: Restart service uses: appleboy/ssh-actionmaster with: host: ${{ secrets.HOST }} username: ${{ secrets.USERNAME