NW SSL 证书管家
一句话给客户服务器签证书、续证书,不用记命令、不用登服务器。
> 唤起方式:在对话里说 「启动NW SSL」 或 「启动NW SSL SKILL」(也支持「打开NW SSL」「NW SSL 证书管家」)即可调起本技能。
凭据与执行位置(两种模式):
- 本地模式(说「启动NW SSL」拉起的 5066 工作台):所有 SSH 从你本机发起,客户机密码不出本机。
- SkillHub 付费版(本技能作为付费 Skill 发布后):执行发生在 SkillHub 云端沙箱,由托管后端 sslpay.sinkr.cn 持有客户机凭据并 SSH 执行——这是你已确认的「托管后端版」取舍,密码集中到你自己的服务器。
付费版执行模型(SkillHub 付费网关 + 执行后端)
本技能作为 SkillHub 付费 Skill 发布后,执行发生在 SkillHub 云端沙箱,付费由运行时在对话内闭环完成(支付宝 A2M):
用户对话
│ init / renew(付费操作)
▼
Agent 执行 scripts/skill_runner.py ──POST──> https://sslpay.sinkr.cn/api/resource
│
┌─────────┴─────────┐
│ 未付费 → HTTP 402 │
│ + Payment-Needed │
└─────────┬─────────┘
│ SkillHub 运行时在对话内拉起
│ 支付宝收银台,用户确认支付
▼
运行时带 Payment-Proof 重试同一请求
│
▼
网关验付 → 内联调用执行后端(127.0.0.1:8600)
完成 SSH 签发/续期 → 200 + 执行结果
- 免费操作(list / status / probe)同样打到
/api/resource,但网关直接交付、不触发付费(下方「付费流程」有透明披露)。 - 本技能沙箱内不含任何客户机密码,也不碰资金;密码仅存于后端
sslpay.sinkr.cn的servers.md。 - 付费闸门(网关 8500)与执行后端(8600)都在你自己的服务器(106.55.166.121);nginx 把公网
/api/resource反代到网关,网关验付后再内网调用执行后端。 - 调用示例:
python scripts/skill_runner.py --action status --target oa.sinkr.cn # 免费
python scripts/skill_runner.py --action renew --target oa.sinkr.cn # 付费¥10:触发对话内支付宝支付
python scripts/skill_runner.py --action list # 免费
> 付费路径上脚本不携带后端执行 token;token 仅在你的服务器内网(网关→执行后端)使用,不随 skill 包外发。
付费流程(对话内支付宝 A2M · 透明披露)
本技能对付费操作(init / renew)按次收费 ¥10.00,由支付宝 A2M 在对话内完成,绝不跳出 Agent 对话:
- 触发 402:本地脚本把
action/target打到https://sslpay.sinkr.cn/api/resource;未付费时网关返回HTTP 402 + Payment-Needed头(含 RSA2 商家签名账单)。 - 对话内支付:SkillHub / WorkBuddy 运行时自动拦截 402,在任务流内弹出「本次费用 ¥10.00,确认后继续执行」支付卡片,用户确认即拉起支付宝收银台——无需跳转站外。
- 带凭证重试:用户付款后,运行时自动用
Payment-Proof头重试同一请求。 - 验付并交付:网关调
alipay.aipay.agent.payment.verify真实验付 → 内联调用执行后端 SSH 完成真正的签发/续期 → 返回200 + 执行结果。 - 幂等:同一订单 24h 内重复请求只履约一次,不会二次扣费(已付费意图会被网关短路直接交付)。
免费操作(list / status / probe)不产生 402、不收费,网关直接交付。完整链路与字段见 references/402-payment.md。
零 · 唤起即启动本地工作台(自动开页面)
用户说「启动NW SSL / 启动NW SSL SKILL」后,Agent 除加载本说明外,还应自动拉起本地 Web 工作台并打开页面,让用户直接在浏览器里加服务器、看状态、点按钮付费,而不必记命令。
标准动作(Agent 执行):
1. 运行 web/start.sh(幂等:5066 已在监听则跳过),用托管 venv 后台启动 web/app.py,监听 127.0.0.1:5066。
2. 确认监听后,用 present_files 打开 http://127.0.0.1:5066/(内置浏览器预览面板)。
3. 若 config/servers.md 尚未配置,提示用户在页面「+ 添加服务器」录入,或把服务器信息发来由 Agent 生成 servers.md。
> ⚠️ 与免费版「证书管理工作台」完全独立、互不干扰:免费版是独立的 Flask 项目 ~/work/openclaw/cert-workbench(配置 cert-workbench/servers.md,你已配过服务器,由 打开工作台.command/start.sh 唤起,经 SSH 调 ssl-cert-manager/scripts/cert-manager.sh 干活,跑在 127.0.0.1:5055);NW SSL 跑在 127.0.0.1:5066(配置 nw-ssl-skill/config/servers.md,产品化版本、供普通用户按次付费使用)。两者端口不同、配置不同、代码不同,互不影响,可同时运行。
页面能力:加服务器、免费巡检证书状态;点「初始化」或「更新证书」弹出执行确认框,确认后经 X-API-Token 鉴权直连后端执行。本地 5066 工作台为作者自用直连通道,不向客户收费;面向客户的按次付费 ¥10 由 SkillHub 平台在对话内闭环(见「付费版执行模型」)。
免费 / 付费边界
| 能力 | 命令 | 本地 5066 工作台 | SkillHub 付费版 |
|---|---|---|---|
| 查看服务器清单 | sslctl.py list |
免费 | 免费 |
| 巡检证书到期状态 | sslctl.py status [名称] |
免费 | 免费 |
| 探测证书来源(nginx / Tomcat) | sslctl.py probe <名称> |
免费 | 免费 |
| 初始化(装 acme.sh + 签发 + 部署) | payment_gate.py --action init |
确认执行(自用) | ¥10 / 次(对话内支付宝支付) |
| 续期(重签 + 部署 + reload) | payment_gate.py --action renew |
确认执行(自用) | ¥10 / 次(对话内支付宝支付) |
本地 5066 工作台为作者自用直连通道,点确认即执行、不收钱;面向客户的按次付费(¥10)由 SkillHub 平台在对话内闭环完成:Agent 调用 scripts/skill_runner.py 把 action/target 打到付费网关 /api/resource,网关返回 HTTP 402 + Payment-Needed,SkillHub 运行时在对话内拉起支付宝收银台,用户付款后带 Payment-Proof 重试,网关验付再内联交付真正的签发/续期结果(不依赖任何外发的执行 token)。
使用效果预览
配好服务器清单后,你能看到的界面类似这样:每台服务器的域名、部署形态(nginx / Tomcat)、到期日、剩余天数、状态、签发机构一目了然。
- 未托管的机器显示「初始化」——首次接管需要装 acme.sh 并签发证书。
- 正常的机器到临近过期时会显示「更新证书」——本地工作台点确认即自动重签 + 部署 + reload(自用直连);SkillHub 付费版则走对话内支付宝 A2M 按次付费 ¥10(见「付费版执行模型」)。
- 点击按钮后,本地工作台经
X-API-Token鉴权直连后端执行(自用通道);而 SkillHub 付费版不携带任何外发 token,一律经/api/resource网关触发 402 → 对话内支付宝支付 → 网关验付后内联交付,后端 SSH 到对应服务器操作。
> 说明:上图是配套的可视化工作台界面,用于免费巡检和查看状态;本 skill 的核心能力通过对话 / 命令触发,无需打开这个页面也能用。
一、先配好服务器清单
复制 config/servers.example.md 为 config/servers.md,一行一台:
| 名称 | 主机 | 用户 | 端口 | 域名 | 证书目录 | 密码 | 自动续期 | 备注 |
|---|---|---|---|---|---|---|---|---|
| 客户A | 1.2.3.4 | root | 22 | oa.xxx.com | nginx |
- 密码留空 = 用 SSH 密钥(推荐):先
ssh-copy-id -p 22 root@IP - 证书目录留空 = 自动从 nginx 配置里探测
servers.md里有明文密码,只留在本机,不要提交到 git、不要打包发出去
也可以用命令加:
python scripts/sslctl.py --config config/servers.md add --name 客户A --host 1.2.3.4 --domain oa.xxx.com --password 'xxx'
新增前会先试一次 SSH,连不上就不写进配置。
二、免费巡检(随时可用)
python scripts/sslctl.py --config config/servers.md status
python scripts/sslctl.py --config config/servers.md status 客户A
返回每台的状态:ok / warning(≤30天) / expired / unmanaged(还没托管) / unreachable(SSH 连不上),以及到期日、剩余天数、签发机构、nginx 还是 Tomcat。
三、本地 5066 工作台:确认执行(自用直连)
点「初始化」或「更新证书」→ 弹出执行确认框 → 确认后经 X-API-Token 鉴权直连后端 sslpay.sinkr.cn/api/v1/run 执行。本工作台为作者自用直连通道,不向客户收费,靠内置共享 token 鉴权。
按当前状态选择正确的 action:
- 状态是
unmanaged(服务器没装 acme.sh)→ 用 init - 状态是
ok/warning/expired且managed: true→ 用 renew
执行命令(经网关转发到后端):
python scripts/payment_gate.py --action init --target oa.xxx.com --config config/servers.md
python scripts/payment_gate.py --action renew --target oa.xxx.com --config config/servers.md
> 面向客户的按次付费(¥10)不走本地工作台,而是 SkillHub 平台对话内付费:Agent 调用 scripts/skill_runner.py 把 action/target 打到付费网关 https://sslpay.sinkr.cn/api/resource,触发 402 → 对话内支付宝支付 → 网关验付后内联交付真正的签发/续期(见「付费版执行模型」)。
四、安全与鉴权说明
- 本地 5066 工作台(作者自用直连通道)经
X-API-Token鉴权后调用后端/api/v1/run;后端为「带 token 即执行」模型,token 即执行凭证(该 token 随 skill 包外发,泄露风险暂缓治理,见 §六 / 待办)。 - 面向客户的按次付费(¥10)不依赖任何外发 token:
skill_runner.py只把action/targetPOST 到/api/resource付费网关,由网关返回 402、SkillHub 运行时拉起支付宝、用户付款后带Payment-Proof重试、网关验付后内联调用执行后端完成真正的签发/续期;本 skill 代码本身不处理资金、不持有客户机密码。 - 防绕过已落地:付费闸门(网关 8500 + 402 + 验付)已部署,客户付费路径强制经过网关,绕过
/api/resource直连/api/v1/run会因缺 token 返回 401 而无法执行,从机制上杜绝「不付费就执行」。
五、两种部署形态的坑(排查必看)
nginx:证书目录自动从 nginx -T 的 ssl_certificate 探测出来。
Tomcat(JKS):从 server.xml 里带 keystoreFile 的 Connector 读出 keystore 路径、密码、别名;server.xml 没写 keyAlias 时用 keytool -list 找 PrivateKeyEntry 的别名。签发后 PEM → PKCS12 → JKS,导入前备份,失败回滚,最后重启 Tomcat。
宝塔面板机器(最常见):
- 强制 HTTPS 会把 HTTP-01 验证请求 301 跳走。改成三段式变量跳转,给
/.well-known/开例外:
if ($server_port !~ 443){ set $ssl_redir 1; }
if ($uri ~ "^/\.well-known/acme-challenge/"){ set $ssl_redir 0; }
if ($ssl_redir = 1){ rewrite ^(/.*)$ https://$host$1 permanent; }
- root 的 umask 是
0077,验证文件权限 600 导致 nginx worker 读不到返回 403。用默认 ACL 兜住:
setfacl -m d:u::rwx,d:g::rx,d:o::rx $WEBROOT/.well-known
setfacl -m d:u::rwx,d:g::rx,d:o::rx $WEBROOT/.well-known/acme-challenge
- 证书目录约定:
/www/server/panel/vhost/cert/<域名>/,文件名fullchain.pem+privkey.pem。
判定「是否已托管」不能只看 /root/.acme.sh/<域名> 目录存不存在——历史遗留的 acme.sh 会让你误判。本技能会额外比对 nginx 实际在用的证书是不是这个 acme.sh 签发的。
六、注意事项
- 续期默认纯手动:不在服务器装定时任务,避免不可控的自动变更。清单里「自动续期」列填
1才会装 cron - Let's Encrypt 有签发限频(同域名每周 5 张重复证书),
--force别连着反复跑 - 证书有效期在缩短(2027 年起 64 天、2028 年起 45 天),建议保持巡检习惯
- 依赖:
pip install paramiko;本地执行封装(payment_gate.py / skill_runner.py)零 pip 依赖——payment_gate.py 自用直连转发与X-API-Token鉴权,skill_runner.py 打/api/resource并处理 402 付费握手,均不持有客户机密码
七、文件说明
| 文件 | 作用 |
|---|---|
scripts/skill_runner.py |
SkillHub 付费版执行封装:统一把 action/target POST 到付费网关 https://sslpay.sinkr.cn/api/resource;付费操作触发 HTTP 402 + Payment-Needed,由 SkillHub 运行时对话内拉起支付宝,付款后带 Payment-Proof 重试,网关验付后内联交付执行结果。不携带任何后端执行 token。 |
scripts/sslctl.py |
证书引擎(跑在后端,不在本技能沙箱内) |
scripts/payment_gate.py |
本地 5066 工作台执行网关(作者自用直连通道):带 X-API-Token 转发 action/target 到后端 /api/v1/run,不碰资金、不持有密码 |
scripts/cert-manager.sh |
跑在客户机上的签发脚本 |
scripts/tomcat-install.sh |
PEM → JKS 并重启 Tomcat |
config/servers.example.md |
本地模式服务器清单模板(复制为 servers.md) |
backend/ |
托管执行后端源码(部署于 106.55.166.121,对外 sslpay.sinkr.cn):api.py(执行后端 8600,带 X-API-Token 鉴权,收到 action 即 SSH 执行)+ payment_gateway.py(付费网关 8500,承接公网 /api/resource,返回 402 / 验付 / 内联交付)+ servers.example.md + start.sh |
references/402-payment.md |
付费流程权威说明:支付宝 A2M 资源端点 /api/resource、¥10.00、402 触发→运行时对话内支付宝→Payment-Proof 重试→验付交付、安全边界与 token 泄露待办。 |