Files
blog/README.md
T
zqlit 5f27ad321d chore(备份): 异地备份定案为 OpenList 离线 bundle,撤销全部 git 辅仓
用户定案:「辅助仓就用 openlist,其他不再考虑」。
据此把前一轮为 Gitee 铺的路全部收回,git 远端只剩 CNB 一个。

一、git 配置收口
- `pushall` 别名 `origin + gitee` → `!git push origin main`(只推唯一远端)
- 移除 `gitea` remote(自建 23.254.236.47:3001)—— 远端仓库本身没删,
  需要时可 `git remote add` 恢复;改动前配置存
  `.workbuddy-backup/git-remotes.20261006-211516.txt`
- 确认无 gitee 相关 credential 残留

二、发布链路去 Gitee 化(6 处)
- `deploy/editor-api/bootstrap.sh`
    · 删掉 GITEE_URL / GITEE_SSH_KEY 两个变量与「没给私钥就降级」的分支
    · PUSH_REMOTES 默认 → origin
    · 原「配 gitee 辅仓远端」一节改为「清理退役远端」循环(gh/gitee/gitea),
      让从旧部署续用的工作区自动恢复干净
- `docker-compose.editor.yml`、`editor-api/server.mjs` → 默认值 origin
- `editor-api/README.md` → 变量表同步
- `editor-api/Dockerfile` → 注释里的「CNB / GitHub」改「CNB」
- `blog-admin/src/routes/rss/tools.ts` → deploy-notify 的注释里
  「与 Gitea Actions 的构建通知配套」改为中性描述
  (该轮询链路 2026-10-04 起已被 CNB 国内节点直传取代)

三、`scripts/setup-cnb-remotes.sh` 重写为单远端模式
- 去掉 GITEE_URL / GITEE_TOKEN 参数、校验、凭据写入与自检提示
- 新增「清理退役远端」步骤
- 凭据处理改为「已存在空的 credential.helper 就不再添加」,
  不再用 --replace-all —— 本仓另有一个从 `$HOME/.workbuddy/secrets/cnb-token`
  读令牌的自定义 helper,那是有效的,不能被脚本抹掉

四、备份升级为「唯一辅仓」的配置
- 保留份数 3 → 7(一周窗口;每份 605.5 MB ≈ 4.2 GB,F50 有 256 GB)
    · `scripts/backup-task.cmd` 默认参数 --keep 7
    · `scripts/backup-bundle.mjs` 的 KEEP 默认值同步为 7
      (原先写的是 2,一直被命令行参数掩盖着)
- 远端目录 `/本地/备份` → `/本地/备份/blog-bundle`:
  根目录是用户自己在用的(放着 github-zqlit-*、local-repos-* 等手工备份),
  实测发现直接放根下的 bundle 已被清掉 —— 改子目录隔离,避免混放与误删

五、新增 `scripts/backup-run.mjs`:备份的推荐入口 + 失败告警
- 读 `.workbuddy-backup/openlist-backup.env`(只补空缺,环境变量优先)
- 跑 backup-bundle.mjs 并实时透传输出,同时留一份日志尾部
- 退出码非 0 → 经 `scripts/send_mail.js` 发告警邮件(附日志尾部与常见原因);
  成功默认不发,`--notify-success` 才发
- 退出用 `process.exitCode` 而非 `process.exit()`,避免截断未排干的 stdout
- 发信失败不改判备份退出码 —— 通知不该掩盖真正的故障
- 理由:这是当前**唯一**的异地备份,而「每天自动跑」的任务最典型的失败模式
  恰恰是静默的(F50 被带出门、换了网段、OpenList 没起来、口令改过……),
  没有告警就要等到真要用备份那天才发现
- `scripts/backup-task.cmd` 改调它

六、文档
- `架构总览.md`
    · §1.2 地址地图:备份行改指 F50/OpenList;通知行补「兼做备份失败告警」
    · §2 旅程图:双推改单推,并说明备份换了介质
    · §5.1 / §5.2 推送与远端:只剩 origin;补「已移除远端」表与恢复命令;
      GitHub 退役记录保留并补上「CI 定义也已删除」
    · §5.3 由「辅仓选型」改为「异地备份的定案」—— 明确不走 git 远端;
      平台对比数据保留备查,并注明 `bin/linux/hugo` 出库不必再做了
    · §5.6 补「唯一备份」定位、专属子目录、失败告警、keep 7、SMTP 配置键,
      实测数据更新为本次复测值
    · §6 待办:#2 定案、#3 不必做、#4 已移除、#8 已更新、#10 定位升级,
      新增 #11(F50 目录使用约定)
- `CNB构建落地方案.md` §4.0:双远端改单远端,脚本示例去掉 Gitee 参数
- `README.md`:推送说明改单推;脚本表补 backup-run.mjs

实测(2026-10-06,本轮复测):
  bundle 7.4s / AES-256-GCM 加密 1.3s / 上传 19.2s(31.6 MB/s)
  / 读回 sha256 一致 → 端到端 60.6s,退出码 0
  告警邮件链路已实测(发出一封「备份成功」验证信)

★ 一处过程记录,供以后避免重复踩坑:
  中途我把「本机沙箱里 `env -u ... cmd > file` 会让输出整个消失」
  误判成 process.exit 截断 stdout,并据此改了日志实现;
  随后用 `env -u FOO echo hi > file`(同样零输出)证伪 ——
  那是沙箱文件重定向的伪影,与脚本无关。相关改动已回滚,
  只留下本身无害的 process.exitCode 写法。
2026-10-06 21:27:28 +08:00

161 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 优世界博客(usj.cc)
Hugo 静态博客 + 自研评论后端 + 写作后台。
**构建与发布跑在腾讯云 CNB**(国内节点),单次发布约 3.5 分钟,境内/境外两条线路一次推完。
> 架构全貌、迁移前后对比、运维要点 → [`架构总览.md`](架构总览.md)
---
## 一、项目构成
| 子系统 | 位置 | 技术栈 |
|---|---|---|
| **内容** | `content/`、`themes/Ying/` | Hugo 0.128.2 extended + Ying 主题 |
| **评论后端** | `blog-admin/` | artalk-cf:Cloudflare Workers + D1 + KV(`api.200181.xyz`) |
| **写作后台** | `write-server/`(线上 `post.usj.cc`)、`write/`(本地 Windows) | Next.js |
| **发布** | `.cnb.yml`、`deploy/` | CNB 流水线 + Dockerfile |
---
## 二、目录结构
```
blog/
├── .cnb.yml # ★ CNB 流水线(push + 每日定时)
├── deploy/Dockerfile # 构建镜像(hugo 二进制由 bin/linux/hugo 提供)
├── bin/linux/hugo # Hugo extended 0.128.2(linux/amd64,供 CNB 构建用)
├── content/
│ ├── posts/<年>/<日期>-<标题>/ # 文章(Page Bundle,index.md + 图片)
│ ├── about.md / links.md / circles.md / archives.md
├── themes/Ying/ # 主题(layout / assets / data)
├── static/ # 原样复制进产物(emotion 表情、image、js …)
├── blog-admin/ # 评论后端(artalk-cf)
├── write-server/ # 线上写作后台
├── write/ # 本地写作前端
├── scripts/ # 各类工具脚本(见第六节)
├── hugo.toml # Hugo 主配置
└── 架构总览.md # ★ 架构文档
```
---
## 三、内容写作
### 文章结构
每篇文章是一个 **Page Bundle**:
```
content/posts/2024/2024-05-01-文章标题/
├── index.md # 正文
└── 配图.jpg # 同目录图片(可用相对路径引用)
```
### URL 规则
由 front matter 的 `slug` 决定(`hugo.toml` 里 `permalinks.post = "/:slug"`):
```yaml
---
title: "我的文章"
date: 2024-05-01
slug: "my-post"
---
```
生成 `https://usj.cc/my-post.html`(uglyURLs,带 `.html`)。
### 隐藏文章
在 front matter 加 `status: hidden`。构建前 `scripts/add_draft_to_hidden.py` 会把它转成
`draft: true`,**不出现在列表里,但直达链接仍可访问**。
### 本地预览
```bash
hugo server -D # 含草稿
```
---
## 四、发布流程
```
写作(write-server / write/)
│ git pushall
▼
CNB 主仓 zqlit/blog ──触发──► CNB 流水线(国内节点,约 3.5 分钟)
├─ Hugo 构建
├─ 同步到又拍云(境内源站)
├─ 刷新又拍云 CDN
├─ 刷新多吉云 CDN
├─ 部署 EdgeOne Pages(境外线路)
└─ 邮件通知
```
- **推送**:`git push origin main`(`origin` = CNB 主仓,**唯一远端**,触发构建)
—— `git pushall` 是同义的别名
- **异地备份**:**不走 git 远端**。本机计划任务每天 03:30 把整仓 bundle
加密后传到中兴 F50 上的 OpenList(见 `架构总览.md` §5.6)
- **触发**:推送到 `main`;另有每日 `0 9 * * *`(北京时间)定时构建
- **密钥**:全部来自 CNB 密钥仓库 `zqlit/blog-secrets`,经 `.cnb.yml` 的 `imports` 注入,
**仓库里没有任何明文密钥**
- 改动 `main` 即自动上线,本地无需构建
---
## 五、三个子系统
### 内容系统
Hugo + Ying 主题。`hugo.toml` 控站点信息、永久链接、Artalk 地址、弹幕等。
### 评论系统(`blog-admin/`)
自研的 **Artalk v2 兼容服务端**,跑在 Cloudflare Workers + D1(SQLite)+ KV:
- 前端用官方 Artalk 客户端(`themes/Ying/assets/js/libs/Artalk.js`,本地打包,非 CDN)
- 后端 API 基址 `https://api.200181.xyz`(评论 `/api/v2/*` 与 RSS 订阅 `/api/*` 同一 Worker)
- 部署:`cd blog-admin && npm run deploy`(详细步骤见 `blog-admin/README.md`、`部署清单.md`)
### 写作后台
- `write-server/`:线上版(Next.js),部署在独立主机
- `write/`:本地 Windows 版
---
## 六、常用脚本(`scripts/`)
| 脚本 | 用途 | 在哪跑 |
|---|---|---|
| `add_draft_to_hidden.py` | 构建前把 `status: hidden` 转成草稿 | **CI** |
| `refresh_cdn.js` | 刷新多吉云 CDN(零依赖) | **CI** |
| `send_mail.js` | 构建结果邮件通知(零依赖 SMTP) | **CI** |
| `setup-cnb-remotes.sh` | 切换/重建 git 远端(只有 CNB 一个;顺手清掉退役远端) | 本机 |
| `backup-run.mjs` | 备份的推荐入口:跑 `backup-bundle` + **失败时发告警邮件** | 本机/计划任务 |
| `backup-bundle.mjs` | 整仓 bundle → AES-256-GCM 加密 → WebDAV 传中兴 F50(见 架构总览 §5.6) | 本机/计划任务 |
| `backup-task.cmd` | 上面的计划任务入口(每天 03:30;**内容必须全 ASCII**) | 计划任务 |
| `optimize_images.js` | 图片批量压缩优化 | 本机 |
| `generate_circle_data.js` | 抓友链 RSS 生成朋友圈数据 | 本机 |
| `update_link_lite_json.ps1` | 友链 `links.yaml` → JSON | 本机 |
| `add_ancient_chars.py` / `check_ancient_chars.py` / `merge_chars.py` | 字体生僻字增补与校验 | 本机 |
| `cleanup_duplicates.js` / `migrate_slugs.js` | 一次性维护脚本 | 本机 |
> `deploy_*.sh`(又拍云 / EdgeOne / 定时)是本机手动部署的旧入口,**日常已不需要**——
> 推送 `main` 由 CNB 自动完成。
---
## 七、相关文档
| 文档 | 内容 |
|---|---|
| `架构总览.md` | **当前架构全貌**(子系统、发布链路、迁移前后对比、运维要点) |
| `CNB构建落地方案.md` | 迁 CNB 的实施方案与实测数据 |
| `代码源与构建平台选型.md` | 平台对比(CNB / Gitee / GitLab / EdgeOne / 阿里云 ESA) |
| `砍COS改造步骤.md` | 腾讯云 COS 下线记录 |
| `blog-admin/README.md` | 评论后端完整说明 |
| `blog-admin/部署清单.md` | 评论后端部署步骤 |