核心能力 · Five Capabilities
每个能力先回答"业务方原本要付什么代价",再补一行技术细节。所有能力共享一条铁律:业务方不碰服务器 — 不 SSH、不写 PM2 ecosystem、不改 Caddyfile、不手抄 .env,一切走 POST /api/deploy 一个 zip,网关统一兜底 build、路由、密钥、回滚。
查看详情
查看详情
查看详情
查看详情
查看详情
架构 · Trigger → Pipeline → 13 managed apps
两条触发路径(agent 手动 POST / GitHub push)汇进同一条 enqueue,异步管线串行跑 13 个 phase,左列是主链路、右列是安全网(snapshot / caddyDiff / smoke / rollback / vault),跑通后由 Caddy 把每个 host 反代到对应 PM2 进程。
关键里程碑 · Timeline
4/23 一天把同步老脚本重写成异步管线,4 月底补自助 skill + prefix 密钥注入,5/9 加审计 + IP 白名单两层防御,5/12 v2 灵魂版本一次性补齐 host 必填 + smoke + 回滚 + vault,5/17 接 GitHub 自动部署收尾。★ 标记的是结构性里程碑。
名场面 · 1 个最值钱的坑(深度)
这条坑没有报错、没有日志告警 — deploy 显示成功,域名却悄悄 404。修法看似就是"加个必填校验",但它背后是"路由 host 由 deployer 隐式计算 + agent 必然偶尔漏字段"两条约束叠加 — 任何把 host 当"约定"而非"声明"的方案,都注定某次忘填就把生产 host 替换成没人用的默认值。
路由 host 不能靠隐式默认:为什么要 host 必填 + caddyDiff 守卫
展开根因 / 修法 / commit / 代码 / 沉淀
- 症状
- 某次 deploy 忘传 manifest.host,deployer 用隐式默认 <project>.mvp.restry.cn 重写了 Caddy route,把真实生产 host(如 wx.mvp.restry.cn)静默踢下线。deploy 任务全程 succeeded,但公网访问 404。wx-gateway / wx-gateway-pucs 每次 agent 漏字段就中招一次。
- 根因
- 路由 host 的单一真相源是"约定"而非"声明" — deployer 在调用点用 <project>.<baseDomain> 兜底。而触发方是 AI agent,非确定性:它一定会偶尔漏掉 host 字段。在"漏了就用默认值覆盖"的世界里,这不是概率问题,是必然问题 — 只是不知道哪次。
- 修法
- (1) manifest.host 必填,空字符串直接 400 Missing required field: host,删掉隐式默认。(2) caddyDiff 守卫:PATCH 前快照 route 的 host 集合,PATCH 后比对,deploy 前存在、deploy 后消失的 host = 回归 → 自动 rollback。(3) 快照 .caddy-routes.json 存项目目录内、随原子 swap 复制前进;首次部署无快照则 fallback 到 live caddy 查询。
- commit
- 71abf42 v2 灵魂版本一次性落地 host 必填 + caddyDiff + smoke + rollback;配套 caddyDiff.test.js 7 case + manifestHost.test.js 5 case 锁回归。
// lib/caddyDiff.js — PATCH 后比对,丢 host 即让调用方回滚 const before = await snapshotHosts(project) // 部署前 host 集合 await caddy.upsertRoute(project, manifest.host, port) const after = await liveHosts(project) // PATCH 后实测 const lost = before.filter(h => !after.includes(h)) if (lost.length) throw new Error(`caddy regression: lost ${lost}`) // → rollback.restore
当前现状 · Status
不写"一切正常 / 运行良好"这类空话。下面五个分组每条都对应一个可在 git log / lib / inventory 里 grep 到的真实事实:生产部署 / 在管资产 / 安全态 / 最近变动 / 运维状态。
生产部署
查看 5 条细节
- 控制台 · deploy.mvp.restry.cn :9800 · Express 单进程,PM2 名 mvp-deployer
- 密钥注入:systemd EnvironmentFile 注 MVP_DEPLOYER__*,ecosystem 只声明非密配置
- 运行栈:裸金属 + PM2(interpreter:none 跑 shell)+ Caddy Admin API 动态路由
- 任务持久化:tasks.json 存最近 50 条 task,重启把 running 标记为 crashed
- 自助接入:skill.mvp.restry.cn 发 /skill.zip + 安装说明,业务方拉了就能发
在管资产规模
查看 4 条细节
- 13 个 app 在管,Caddy 反代真实 hosts:wx · wxmsg · design · echo · menshen · packhorizon · cspy · shutiao-world · recap · skill
- 类型:node 常驻进程(install+build)+ static 纯托管(skip build)两类
- 预检:GET /api/inventory 一次返回 per-project manifest / PM2 / Caddy route / envKeys / disk / 已用端口 + next_suggested
- 密文安全:inventory 从不返回 secret 值,仅白名单非敏感 key(如 DATABASE_URL)
安全态(token = host root,层层收口)
查看 4 条细节
- L2 IP 白名单:IP_ALLOWLIST CIDR/IP 在 token 校验之前过滤,离网泄露的 token 直接无效;命中拦截回显 yourIp 便于排查
- 审计自保:NDJSON 审计层 + /api/audit 用独立 AUDIT_READ_TOKEN,部署 token 泄露读不到自己的取证日志;默认不信 X-Forwarded-For 防伪造
- RCE 收口:/api/exec/<project> 等价 host root,正是 IP 白名单 + token 隔离的直接动机
- 双 token:webhook 走 HMAC-SHA256(与 Bearer 解耦)· dashboard 走 session cookie HMAC + 微信 finalize 验签
最近主要变动(git log)
查看 8 条 commit
- 7619663 fix: handle ms-epoch timestamp in wx login — 微信登录时间戳秒/毫秒都兼容
- 15cad71 Add dashboard auth and sync-skill install guide — 控制台加微信鉴权
- 7224b8f Make auto deploy polling daytime scheduled — 轮询改白天 09–23 CST
- 6c24291 feat: add GitHub auto deploy — ★ webhook + 轮询双触发上线
- 71abf42 feat(deployer): host-required, no auto-migrate, smoke+rollback, vault — ★ v2 灵魂
- 31358cf feat(security): IP allowlist (L2 defense) with yourIp echo
- d09175e feat(audit): NDJSON audit log layer + /api/audit endpoint
- 17787b1 feat: add GET /api/inventory for full deployment context
运维状态
查看 5 条细节
- node:test 36 case 本地全绿:host 校验 5 + caddyDiff 7 + smoke 11 + mergeEnv 4 + vault 6 + credentials,改管线必跑
- 自愈链已就位:snapshot → caddyDiff → smoke → rollback,smoke 探 https://<host>/ + smokePaths,接受 {200,204,301,302,307,308}
- 回滚保留 3 份:/opt/mvp-apps/.rollback/<p>-<ts>/,每次新快照剪旧的;失败时换回 + 改回 Caddy 上游 + pm2 restart --update-env
- vault 容错:探 vault / menshen-vault on PATH,缺失或失败仅 WARN 不阻断,降级用前缀 env
- auto-deploy 调度:webhook 即时 + 轮询兜底(默认 10 分钟),仅白天窗口跑,避免凌晨半坏部署
未结清债务 · Open Debt
不写"P1 待办若干"这种模糊罗列。每条 4 列:优先级(P0 立刻 / P1 本周 / P2 排期) · 工作量(S < 0.5d · M 1–2d · L 3d+) · 待办 · 现状是什么(看了就知道离修好还差什么)。来源:CHANGELOG.md v2 risks 清单 / README 已知问题 / 近 34 commits / 实际运维。