用 Cloudflare Workers 定时启停 Hermes Cloud 完整教程

Hermes Cloud 可以在自己的 Nous 托管平台托管 Agent,不过与 OD 等提供hermes 托管的云服务商家收取定额月付不一样,Hermes 在 Nous Portal 常驻运行时会计入计算费和存储费;实例停止后只保留存储费。对于每天只在固定时段使用的实例,定时停止能把非使用时段从运行计费切换为停止计费。

实例每天运行 8 小时、停止 16 小时。没有全天在线需求时,这 16 小时不必继续承担计算时间。后文的定时规则不是为了让 Hermes 更方便地开关,而是为了稳定地执行这段运行/停止计费切换。实例费用按日、按实际运行时间计;停止后仅收存储费。停止实例的公开价格是 $0.03/天,连续保留 30 天约 $0.90;这属于持续保留实例的实际最低成本,不是合同式“最低月供”。Small 实例持续运行则约 $0.29/天,30 天约 $8.70,还不含模型推理和工具调用。Nous Plus 的 $20/月 是可选订阅,不是为了使用 Hermes Cloud 而必须购买;云托管会从 Credits 单独扣除。

Hermes Cloud 支持在 Nous Portal 手动启动和停止实例,但后台暂时不能按多个时段自动切换服务器状态。通过用 Cloudflare Workers 的免费资源做云实例级启停,电脑关机或离线也不影响执行。

相关阅读Hermes Agent 搭配官方自有Nous Portal,API、云端工具与 Hermes Cloud 托管,Plus 邀请首月 5 美元

这并不适合所有实例。Telegram、Webhook、全天 Cron 或需要随时响应的 Hermes 任务,必须安排在运行时段内;如果这些工作不能中断,就不应按本文方式停止整台实例。

定时表

北京时间实例动作下一时段
08:00启动运行到 10:00
10:00停止停止到 17:00
17:00启动运行到 23:00
23:00停止停止到次日 08:00

这里停止的不是 Hermes 里的某个任务,而是承载 Hermes 的云实例。实例停止后,聊天、Cron、消息渠道和其他依赖在线进程的任务都会停下;重新启动后,持久化数据仍会保留。

Nous Portal 中的 Hermes Cloud 实例列表与运行状态
Nous Portal 的实例管理页。截图拍摄于启动核验阶段,状态会随定时任务变化。

操作思路

操作不复杂:

  1. Cloudflare Cron Triggers 到点唤醒 Worker。
  2. Worker 按实际 UTC 小时判断目标状态,不直接依赖可能延迟到达的触发事件。
  3. Worker 使用加密保存的 OAuth 刷新令牌连接 Nous Portal MCP。
  4. Worker 只对预先固定的实例执行 start 或 stop,随后同时核对 Hermes 状态和底层计算状态。

Cloudflare Pages 适合托管静态网页,不负责执行这类定时控制任务;这里用的是 Workers。Cron Trigger 会调用 Worker 的 scheduled() 处理器,Cron 时间统一按 UTC 解释。

相关阅读美国人常喝的苹果汁因贸易战影响从中国进口大幅减少

开始前需要准备什么

  • Cloudflare 账户,免费 Workers 计划即可。
  • 已创建的 Hermes Cloud 实例。
  • 能登录 Nous Portal 的浏览器。
  • 本地 Node.js 18 或更高版本,仅用于首次 OAuth 授权。
  • 目标实例的 ID 和名称。

Nous 官方 MCP 可以读取实例状态,也能启动、停止、重启、创建和销毁实例。OAuth 权限面比本文的用途更宽,因此示例将目标 ID 与名称固定,控制入口也只接受 start、stop 两个动作。查看 Hermes Cloud MCP 官方说明

第一步:创建 Worker、KV 和两个密钥

在 Cloudflare 后台打开“Workers 和 Pages”,新建一个 Worker,例如 hermes-cloud-scheduler。

创建一个 Workers KV 命名空间,例如 HERMES_SCHEDULER_STATE,再回到 Worker 的“设置”页面添加 KV 绑定:

变量名:STATE
KV 命名空间:HERMES_SCHEDULER_STATE

然后添加两个加密密钥:

ADMIN_KEY
ENCRYPTION_KEY

在本地生成两个随机值:

openssl rand -hex 32
openssl rand -base64 32

第一行结果用于 ADMIN_KEY,第二行结果用于 ENCRYPTION_KEY。不要把真实值写进 Worker 源码、文章、截图、URL 或公开代码仓库。

KV 用于保存 OAuth 客户端、访问令牌、刷新令牌、启用状态和最近一次执行结果。示例 Worker 先用 AES-GCM 加密,再写入 KV;加密密钥只保存在 Cloudflare Secret 中。

第二步:部署 Worker 代码

部署前先在示例 Worker 中填入这两个值:

const TARGET_ID = 'REPLACE_WITH_YOUR_INSTANCE_ID';
const TARGET_NAME = 'REPLACE_WITH_YOUR_INSTANCE_NAME';

将代码粘贴到 Cloudflare 的 Worker 编辑器并部署。示例已做了这些限制:

  • 公共首页只能看到服务版本、时区和时间表,不能控制实例。
  • 管理请求必须在 Authorization 请求头中携带 ADMIN_KEY。
  • 不接受从 URL 查询参数传入管理员密钥。
  • 目标实例同时校验 ID 与名称。
  • 只允许启动和停止,不开放创建、销毁或任意实例 ID。
  • 每次执行前读取状态,执行后继续轮询计算状态,失败最多重试三次。
  • OAuth 访问令牌接近过期时自动刷新。

程序按实际执行时的当前时间决定目标状态。某次触发即使延迟到达,也不会在错误时段把实例重新启动。

第三步:完成一次 OAuth 授权

Nous Portal MCP 使用 OAuth、PKCE 和动态客户端注册。首次连接需要在浏览器中授权,之后由刷新令牌续期,电脑无需持续在线。

本次部署时,OAuth 客户端注册只接受 localhost 或 127.0.0.1 回调,不能直接使用 Cloudflare Worker 地址。做法是让本机接收一次回调,再把授权结果传给 Worker 的受保护 /bootstrap 入口。

将以下三个文件放进同一目录:

  • OAuth 初始化脚本(其中保存 Worker 地址)
  • 本地密钥配置文件,复制后改名为 setup-secrets.json
  • 已部署的 Worker 地址

编辑 oauth-setup-example.mjs 中的 Worker 地址,并在 setup-secrets.json 填入刚才生成的两个值。然后运行:

node oauth-setup-example.mjs

脚本会在 127.0.0.1:18764 启动一次性回调,并生成 authorize-url.txt。在浏览器中打开该地址,登录 Nous Portal,选择目标实例所在的组织并授权。完成后,脚本会把 OAuth 客户端和令牌传给 Worker,由 Worker 加密写入 KV。

完成后删除本地的 authorize-url.txt、oauth-checkpoint.json 和包含真实密钥的 setup-secrets.json,或至少将它们移动到受保护的密码库。/bootstrap 在已有令牌时会拒绝重复导入。

第四步:启用调度配置

OAuth 导入成功后,使用管理员请求启用调度:

export WORKER_URL="https://你的Worker.workers.dev"
export ADMIN_KEY="你的管理员密钥"

curl -X POST "$WORKER_URL/configure" \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  --data '{"enabled":true}'

启用前,Worker 会先检查目标实例身份。ID 或名称不匹配时会报错,不保存启用状态。

第五步:添加北京时间定时规则

Cloudflare Cron 使用 UTC。北京时间是 UTC+8,因此需要这样换算:

北京时间UTC动作
08:0000:00启动
10:0002:00停止
17:0009:00启动
23:0015:00停止

进入 Worker 的“设置”→“触发事件”→“Cron 触发器”,添加一条规则:

0 0,2,9,15 * * *

一条表达式即可覆盖每天四个时间点,无需建立四条规则。新增或修改 Cron 后,Cloudflare 最多可能需要 15 分钟完成传播。

Cloudflare Worker 的 Cron 触发器设置
Cloudflare 后台已经保存的 Cron 触发器。界面会显示 UTC 时间和下一次运行时间。

第六步:先手动验证,再等待定时触发

先访问 Worker 公共首页,确认版本、时区和时间表。该页面不返回实例 ID、令牌或控制接口。

Hermes Cloud scheduler 的公开时间表
公开状态页显示 Asia/Shanghai、两个启动时间和两个停止时间。

再使用管理员请求查看内部状态:

curl "$WORKER_URL/status" \
  -H "Authorization: Bearer $ADMIN_KEY"

正式启用前,分别执行一次真实停止和启动:

curl -X POST "$WORKER_URL/control" \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  --data '{"action":"stop"}'

curl -X POST "$WORKER_URL/control" \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  --data '{"action":"start"}'

验证时不要只看 RUNNING 或 STOPPED,还要确认底层计算状态已经变为 Running 或 Stopped。实例状态和云计算状态之间可能相差数秒。

这套方案每天消耗多少模型 token

部署过程和日常运行的用量需要分开看。

环节模型 token 消耗
Cloudflare 每天四次 Cron 唤醒0
Worker 查询实例状态0
Worker 调用 MCP 启动或停止实例0
OAuth 刷新令牌0
实例启动后,Hermes 执行聊天、Cron、搜索或其他 AI 任务按实际模型和工具用量计费
使用 Codex 或其他 AI 帮助首次写代码、排错和部署不固定,取决于对话长度、上下文和返工次数

定时 Worker 直接调用 Nous Portal 的 MCP 生命周期接口,不向模型发送提示词,也不要求模型生成回答。因此,自动启停本身不产生模型 token。Cloudflare 记录的是 Worker 请求和计算用量,不是 LLM token。

本次搭建使用了 Codex 协助,但当前任务没有可核验的单次对话 token 明细,不能根据代码长度反推准确数字。手动照本文部署不需要额外 AI token;如果交由 Codex 全程操作,用量会随所用模型、上下文长度和排错次数变化。

Cloudflare 免费额度够不够

以这套用量看,免费额度足够。每天只有四次计划触发,再加少量人工状态检查。Cloudflare Workers Free 当前提供每天 100,000 次请求、每账户 5 个 Cron 触发器;网络等待时间不计入 Worker CPU 时间。

本方案只占一条 Cron 规则。若账户中已有其他 Worker 定时任务,先检查全账户的 Cron 数量;免费额度按账户统计,并非每个 Worker 各有 5 条。

Hermes Cloud 一天大约能省多少

Nous 的公开计费说明为:运行状态按实际在线秒数收取计算费和存储费,停止状态只收存储费;账单按 UTC 日汇总,模型推理和工具调用另计。查看 Hermes Cloud 计费说明

每天运行 8 小时、停止 16 小时,可以用下面的公式估算:

每日实例费用 = 运行日价 × 8/24 + 停止日价 × 16/24

设运行日价为 R、停止日价为 S,本文时段的每日费用就是 R/3 + 2S/3;连续 30 天约为 10R + 20S。这只是实例费用,不含模型和工具用量。Nous 的公开介绍页目前没有列出固定规格价目表,账户后台也可能显示 Standard 等不同规格,计算时请使用自己账单中的运行价和停止价。

暂停或修改自动化

临时停用可以调用配置接口:

curl -X POST "$WORKER_URL/configure" \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  --data '{"enabled":false}'

也可以在 Cloudflare 删除 Cron 触发器。两种方式都只会停止后续的自动操作,不会改变实例当前的运行状态。

修改时段时,同时调整 Cloudflare Cron 表达式和 Worker 中 desiredAction() 的运行时间窗口。只改 Cron、不改目标状态判断,延迟触发或人工补跑时可能得到错误结果。

常见问题与排查

Cron 保存失败并提示达到上限

检查账户下其他 Worker 的 Cron 规则。免费计划每个账户最多 5 个 Cron 触发器,旧 Worker 即使不再使用,只要规则还在就会占用名额。

授权完成后仍显示未连接

检查本机回调是否仍在监听 127.0.0.1:18764,OAuth 的 state 是否匹配,以及 /bootstrap 请求是否使用请求头而不是 URL 参数传递 ADMIN_KEY。

实例显示 STOPPED,但云计算状态还没停止

继续轮询底层 machine.state,直到进入 Stopped、Deallocated 等停止状态。示例 Worker 已包含轮询与重试,不要只依据 Hermes 的状态文字判断结果。

到点没有马上执行

新建或修改的 Cron 可能需要最多 15 分钟传播。进入 Cloudflare 的 Cron Events 和 Workers Logs 查看实际触发与错误记录。

实例停止后 Hermes 的定时任务还会运行吗

不会。本文停止的是承载 Hermes 的云实例,依赖在线进程的任务在停止时段无法执行。需要全天运行的任务应避开停止时段,或改由另一台持续在线的执行环境处理。

这套方案把每天固定的启停操作交给轻量 Worker。电脑离线不影响调度,日常启停也不产生模型 token;Hermes Cloud 只在需要的时段保持在线。

Simon共 2451 篇文章

【声明】:本博客不参与任何交易及中介服务,只记录 VPS 和域名注册优惠,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。

发表评论