Files
blog/README.md
T
zqlit 7abef4ac13 docs: 全量梳理文档结构;补 Gitea 迁移指南 / 架构精简候选;架构总览补证书管家子系统
用户四问:「把项目文件全部理一遍 还有readme文件」「gitea 后面可能还要迁移 帮我写一个迁移文档」
「证书管家做完了吗」「感觉现在架构还是复杂了」

一、文档梳理:根目录 15 个 md → 2 个

根目录只留 README.md(入口)+ 架构总览.md(现状唯一事实源),其余全部归位:

  docs/
  ├── README.md              ← 新增:文档地图(入口 / 当前有效 / 历史归档 三层)
  ├── 证书管家.md             ← 原「函数版证书管家-方案.md」改名
  │                              (它早已是「现状+沿革」文档,标题名不副实 —— 签发早已不在 CF Worker)
  ├── Gitea迁移指南.md        ← 新增
  ├── 架构精简候选.md         ← 新增
  ├── CNB构建落地方案.md / GITEA_SECRETS.md
  └── archive/{平台与选型,功能与修复,主题与内容}/   ← 32 份

- 32 个归档文档统一加 `> 📦 本文档已归档` banner,并指向架构总览
  —— 这个仓库历史文档里全是「权威口径」,混看很容易拿废弃结论当现状
- gitea-backup/ → deploy/gitea/(原名「backup」不准,它是部署包;与其它 deploy 单元并列)
- 新增 md 链接校验(python 脚本,中文路径用 sed 不安全)→ 首轮 18 处断链
  (多一层目录要让 banner 里的相对路径补一个 ../)→ 修正后 0 断链

二、新增 docs/Gitea迁移指南.md(★ 有死线:境外 VPS 11 月到期)

★ 核心价值是「指出迁移面已大幅缩小」:仓库原有的 deploy/gitea/迁移前检查清单.md
(2026-10-04)是为「Gitea + act_runner + 又拍云同步 *整套* 搬迁」写的,**那个前提已经不存在**——
构建归 CNB,runner / upyun-sync / 中转机 / COS 都不需要了。迁移实际只剩「搬数据卷 + 改地址」。

★★ 全文最重要:本仓有 9 处写死了旧地址,按易漏程度排序(1-3 本机,4-5 线上)
  1 本机 .git/config 的 gitea remote
  2 scripts/setup-cnb-remotes.sh 的 GITEA_URL 默认值
  3 deploy/editor-api/bootstrap.sh 的 GITEA_URL 默认值
  4 ★ /srv/editor-api/.env 的 GITEA_URL      ← 漏了会「持续报错但只警告不阻断」,没人发现
  5 ★ /srv/blog 的 gitea remote               ← 同上
  6 docs/GITEA_SECRETS.md
  7-9 架构总览.md / README.md / editor-api/README.md
(不用改:docker-compose.editor.yml、server.mjs、pushall 别名 —— 只引用 remote 名字)

另含:建议新实例改用域名而非 IP(以后搬机器只改 DNS;⚠️ Gitea 28 起只读 ROOT_URL 不读
[server] DOMAIN);rsync 而非 dump(属主必须 uid/gid 1000);切换顺序「先建新的→验证→再拆旧的」;
验证清单强调 `git push gitea --dry-run`;第九节给出「干脆不留这个辅仓」的选项与判断依据。

顺带修掉两个硬伤:
- deploy/gitea/docker-compose.yml 的镜像 tag `1.28.0-rootless` 根本不存在
  (Gitea 28 起去掉 1. 前缀)→ 改 28.0.0-rootless(pin 死,不用 latest)
- deploy/gitea/.gitignore 漏了 backups/(跑一次备份就会把含 secrets 的 dump 写进历史)

三、证书管家核实(结论:已上线运行,2 个遗留)

线上实测:容器 Up (healthy);/preflight 7/7 全过;3 组域名;下次自动续期 04:10。

遗留 ① writeapi.usj.cc 证书没纳管(真问题):nginx 配置在 /www/conf.d/writeapi.usj.cc.conf,
不在 /www/sites/ 管理树里 → 1Panel 的 ssl/upload+sslID 物化碰不到它。
实测仍是 RSA / CN=usj.cc / 到期 2026-12-07,本项目续期不会更新 → 12 月会断。
遗留 ② dnsapi.usj.cc 没上 HTTPS。
(澄清假问题:200181.xyz 公网看到的 LE 证书是 CF 自家边缘证书,与本项目无关)

四、新增 docs/架构精简候选.md(回应「架构还是复杂了」)

结论:复杂度不在件数,在「跨 6 个环境,其中 4 个要自己维护」。国内机 9 个容器里属于本项目的
只有 3 个,能动的只有 2 个。5 个候选 + 建议执行顺序:
  1 停 certimate 容器(工作流已全停用)——先 stop 观察,别急着删
  2 cn-dns-helper 大概率已是遗留(「Worker 侧签发」时代产物;现在签发在国内机且自带 dnsprovider,
    /preflight 显示 CF 凭据可读;Worker 侧 dnsremoted.ts 已无任何引用)
  3 Gitea:迁 or 不留
  4 两套写作前端收敛(本轮不动,先看使用频率)
  5 writeapi.usj.cc 证书纳管(12 月死线)
并明确列出 6 项「必要复杂度,不建议动」。

五、架构总览补齐证书管家子系统(★ 之前完全缺席)

一个完整子系统在「事实源文档」里一个字都没有 —— 这本身就是文档债。补:
- §0 一句话(四→五个子系统)、§1.1 子系统表、§1.2 地址地图两行
- **新增 §5.7 证书管家**:职责划分 / 为什么非要这么分(Worker 免费版 CPU 10ms)/
  三条不能破的红线(Worker 不得签发 · 证书路由只认 Bearer 会话 · 角色必须正着枚举放行)/
  纳管域名表 / 与 certimate 的关系 / 已知遗留
- .cnb.yml 行数 284 → 337(数字漂了);头部更新时间 → 2026-10-06;附录表改指 docs/
- §6 待办:#13(证书遗留)、#14(复杂度盘点)新增;#7 改写为「Gitea 11 月到期,★ 有死线」

六、记忆

.workbuddy/memory/MEMORY.md 新增「文档结构」「Gitea 迁移死线」两节;证书管家节补实测与遗留。
2026-10-06 22:27:36 +08:00

176 lines
8.7 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)(架构唯一事实源)
> 🗂 **想找某份文档** → [`docs/README.md`](docs/README.md)(文档地图)
> 🔧 **要动手改东西** → 先看下面「项目构成」找准子系统,再看对应的专题文档
---
## 一、项目构成(五个子系统)
| # | 子系统 | 位置 | 技术栈 | 部署形态 |
|---|---|---|---|---|
| 1 | **内容** | `content/`、`themes/Ying/` | Hugo 0.128.2 extended + Ying 主题 | 产物分发到 3 个 CDN |
| 2 | **评论后端** | `blog-admin/` | artalk-cf:Cloudflare Workers + D1 + KV | 托管(`api.200181.xyz`) |
| 3 | **写作后台** | `write-server/`(线上 `post.usj.cc`)、`write/`(本地)、`editor-api/`(线上发布入口) | Next.js / 轻量 Node(零依赖) | 独立主机 / 本机 / 国内机容器 |
| 4 | **发布基础设施** | `.cnb.yml`、`deploy/Dockerfile` | CNB 流水线 + 又拍云 + 多吉云 + EdgeOne | 托管(CNB,0 元额度内) |
| 5 | **证书管家** | `deploy/cn-certkeeper/`、`blog-admin/src/lib/acme.ts` | 自研 ACME 客户端(纯 WebCrypto,零 npm 依赖) | 国内机容器(签发)+ CF Worker(只读) |
> 子系统 5 的详细设计与「勿回退的坑」见 [`docs/证书管家.md`](docs/证书管家.md)。
---
## 二、目录结构
```
blog/
├── README.md # ★ 本文(项目入口)
├── 架构总览.md # ★ 架构唯一事实源
├── docs/ # 专题文档(地图见 docs/README.md)
│ ├── 证书管家.md
│ ├── Gitea迁移指南.md # ★ Gitea 换机器时照做
│ ├── CNB构建落地方案.md
│ ├── GITEA_SECRETS.md # ⚠️ 含明文凭据
│ └── archive/ # 已归档:决策期评估 + 已完结方案
├── .cnb.yml # CNB 流水线(push 触发 + 每日定时)
├── content/ # 文章(Page Bundle:index.md + 图片)
├── themes/Ying/ # 主题
├── static/ # 原样复制进产物(表情、图片、js …)
├── hugo.toml # Hugo 主配置
├── bin/linux/hugo # Hugo extended 0.128.2(linux/amd64,供 CNB 构建用)
├── blog-admin/ # 评论后端(artalk-cf)+ 证书管家的只读面
├── editor-api/ # 写作后台的后端(国内机容器里跑的就是它)
├── write-server/ # 线上写作前端(Next.js)
├── write/ # 本地写作前端(Windows)
├── deploy/ # 部署单元
│ ├── Dockerfile # CNB 构建镜像
│ ├── editor-api/ # bootstrap.sh(一键部署写作后台)
│ ├── cn-certkeeper/ # 证书签发 + 部署容器
│ ├── cn-dns-helper/ # DNS-01 辅助
│ └── gitea/ # Gitea 部署包(原名 gitea-backup/)
└── scripts/ # 工具脚本(见第五节)
```
> `data/`、`public/`、`.editor-tmp/`、`.workbuddy-backup/` 等为运行时/构建期产物,**已被 `.gitignore` 忽略**。
---
## 三、内容写作
### 文章结构
每篇文章是一个 **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 # 含草稿
```
---
## 四、发布与留存
### 4.1 一次发布(3 步)
```
① 写作 write-server(网页)或 write/(本地 Windows)
│
② git push git pushall = git push origin main ; git push gitea main
│ ├─ origin → cnb.cool/zqlit/blog (主仓,触发构建)
│ └─ gitea → 23.254.236.47:3001/zqlit/blog (自建 Gitea 辅仓,只推不拉)
▼
③ CNB 流水线(国内节点,约 3.5 分钟)
├─ Hugo 构建 → 同步又拍云 → 刷新又拍云 CDN → 刷新多吉云 CDN
└─ 部署 EdgeOne Pages(境外线路)→ 上报状态 → 邮件通知
```
- **触发**:推送到 `main`;另有每日 `0 9 * * *`(北京时间)定时构建
- **密钥**:全部来自 CNB 密钥仓库 `zqlit/blog-secrets`,经 `.cnb.yml` 的 `imports` 注入
—— **仓库里没有任何明文密钥**
- 改动 `main` 即自动上线,本地无需构建
### 4.2 三个留存层(失效模式不同,不能互相替代)
| 层 | 载体 | 保住什么 | 依赖 |
|---|---|---|---|
| **主仓** `origin` | CNB | 源码 + 触发构建 | CNB 平台 |
| **代码辅仓** `gitea` | 自建 Gitea | 在线可 clone、可按提交追溯 | 自己的机器(⚠️ **2026 年 11 月到期,要迁**,见 `docs/Gitea迁移指南.md`) |
| **离线备份** | 中兴 F50 / OpenList | 完整历史 + 所有对象(加密单文件) | 家庭局域网 |
- **推送**:`git pushall` 依次推 `origin` 与 `gitea`;只推主仓用 `git push origin main`
- 线上写作后台(国内机 `editor-api` 容器)走同一套:`PUSH_REMOTES=origin,gitea`,
**主仓成功即算发布成功**,辅仓失败只警告不阻断
- ★ **两边同一条铁律:任何提交都必须先落到 CNB** —— pull 源只有 `origin`,
只推 `gitea` 的提交后台看不见,下次发布会因 non-fast-forward 被拒
- **离线备份**:本机计划任务每天 03:30 把整仓 bundle(**打包前先 `git fetch --all`**,
否则备的是过期快照)加密后传到 F50 上的 OpenList(见 `架构总览.md` §5.6)
---
## 五、常用脚本(`scripts/`)
| 脚本 | 用途 | 在哪跑 |
|---|---|---|
| `add_draft_to_hidden.py` | 构建前把 `status: hidden` 转成草稿 | **CI** |
| `refresh_cdn.js` | 刷新多吉云 CDN(零依赖) | **CI** |
| `send_mail.js` | 构建结果邮件通知(零依赖 SMTP) | **CI** |
| `fetch_snapshots.sh` | 构建期拉 conf/友链/友圈快照 → `data/` | **CI** |
| `setup-cnb-remotes.sh` | 重建 git 远端(CNB 主仓 + Gitea 辅仓;顺手清退役远端) | 本机 |
| `backup-run.mjs` | 备份推荐入口:跑 `backup-bundle` + **失败时发告警邮件** | 本机/计划任务 |
| `backup-bundle.mjs` | `git fetch --all` → 整仓 bundle → AES-256-GCM 加密 → WebDAV 传 F50 | 本机/计划任务 |
| `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 自动完成。
---
## 六、文档地图
只列导航,完整说明见 [`docs/README.md`](docs/README.md)。
| 文档 | 内容 |
|---|---|
| [`架构总览.md`](架构总览.md) | ★ **当前架构全貌**(五个子系统、发布链路、运维要点、遗留待办) |
| [`docs/证书管家.md`](docs/证书管家.md) | ★ 证书子系统:现状 + 决策沿革 + 勿回退的坑 |
| [`docs/Gitea迁移指南.md`](docs/Gitea迁移指南.md) | ★ Gitea 换机器:**本仓 9 处写死旧地址**的清单 + 验证步骤 |
| [`docs/架构精简候选.md`](docs/架构精简候选.md) | 复杂度盘点与 5 个可精简候选(想「让架构简单点」时看) |
| [`docs/CNB构建落地方案.md`](docs/CNB构建落地方案.md) | 迁 CNB 的实施方案与实测数据 |
| [`docs/archive/`](docs/archive/) | 决策期评估与已完结方案(**不代表现状**) |
| `blog-admin/README.md`、`blog-admin/部署清单.md` | 评论后端完整说明 |
| `editor-api/README.md` | 写作后台 API(含「落盘:写一次,存三处」) |