背景

需要把 Obsidian Vault 打造成自动部署的知识库站点。原来是手动生成 HTML 再 SCP 上传,每次改个错字都要走一遍完整流程。目标:写 Markdown → git push → 网站自动更新

架构

Obsidian(本地编辑) → git push → GitHub Actions(Quartz 构建) → rsync → 腾讯云
  • Quartz v4:Obsidian 专用的静态站点生成器,原生支持双向链接、关系图谱、标签页
  • 站点地址:sop.mistprism.com
  • 仓库:chituhouse/Obsidian(私有)

搭建步骤

1. Quartz 初始化

克隆 Quartz 模板到临时目录,把脚手架文件复制到 Obsidian 仓库根目录:

quartz.config.ts    # 核心配置
quartz.layout.ts    # 页面布局组件
package.json        # 依赖
quartz/             # 框架源码

原有 Vault 文件(.obsidian/.md 文件)移入 content/ 目录——Quartz 只读取 content/ 下的内容。

2. 目录结构设计

content/
├── index.md                    # 首页
├── Projects/Jarvis/            # 项目文档
│   ├── sop-guide.md
│   └── architecture-review.md
├── Topics/                     # 技术主题
│   ├── Claude-Code/
│   └── Quartz/
├── TIL/                        # Today I Learned
└── MOC/                        # Maps of Content

3. 配置要点

quartz.config.ts 关键配置:

configuration: {
  pageTitle: "MistPrism SOP",
  locale: "zh-CN",
  baseUrl: "sop.mistprism.com",
  enableSPA: true,        // 单页应用模式
  enablePopovers: true,   // 链接悬浮预览
  defaultDateType: "modified",
}

字体选择 Inter(正文 + 标题) + IBM Plex Mono(代码)。

4. HTML → Markdown 迁移

把两篇已有的 HTML SOP 文档(共 130KB)转换为 Markdown + frontmatter 格式。要点:

  • 标题从 ## 开始(Quartz 从 frontmatter title 自动生成 #
  • frontmatter 统一标签体系:project/type/topic/status/
  • 表格、代码块、callout 等格式手动校准

5. CI/CD 流水线

.github/workflows/deploy.yml

on:
  push:
    branches: [main]
 
steps:
  - uses: actions/checkout@v4
    with:
      fetch-depth: 0        # Quartz 需要完整 git 历史计算日期
  - uses: actions/setup-node@v4
    with:
      node-version: 22
      cache: 'npm'
  - run: npm ci
  - run: npx quartz build
  - name: Deploy
    run: rsync -avz --delete -e "ssh -i ~/.ssh/deploy_key" public/ user@host:/path/

fetch-depth: 0 是必须的

Quartz 用 git log 计算文件的创建/修改日期。如果 fetch-depth: 1(默认),所有文件日期都是”刚刚”。

GitHub Secrets 需要配置:DEPLOY_SSH_KEYDEPLOY_HOSTDEPLOY_USERDEPLOY_PATH

部署密钥用 ed25519:ssh-keygen -t ed25519 -C "github-actions-deploy"

6. nginx 配置

# Quartz 生成的 URL 没有 .html 后缀
location / {
    try_files $uri $uri.html $uri/ =404;
}
 
# CSS/JS 每次验证(内容随部署变化)
location ~* \.(js|css)$ {
    add_header Cache-Control "no-cache";
}
 
# 图片/字体长缓存(内容稳定)
location ~* \.(png|jpg|jpeg|gif|ico|svg|woff|woff2|webp)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

不要给 CSS/JS 设 immutable 缓存

Quartz 的 index.cssprescript.js 文件名不含 hash,内容随每次部署变化。immutable 会导致用户永远看不到更新。详见 暗色模式排查实录

7. dev-notes Skill 改造

原来的 dev-notes skill 生成 HTML 并 SSH 部署,改为:

  • 生成 Markdown(含 frontmatter 标签)→ 写入 vault content/ 目录 → git push → 自动部署
  • 删除所有 HTML 生成和 SSH 部署逻辑
  • 与 Quartz 的 URL 结构对齐:content/Topics/Foo/bar.mdsop.mistprism.com/Topics/Foo/bar

踩坑记录

Quartz 颜色变量语义

Quartz 的颜色变量名和直觉相反——light 是背景色不是浅色文字,dark 是标题色不是深色背景。详见 暗色模式排查实录

LaTeX 警告

中文字符被 KaTeX 解析为数学公式(如含 $ 的文本)。构建时会报警告,不影响页面渲染,但后续可考虑转义处理。

Claude Code 会话迁移

尝试将 JSONL 会话文件从项目 A 复制到项目 B,/resume 搜索不到。Claude Code 有内部会话注册机制,sessions-index.json 只是缓存不是源。详见 会话迁移排查

成果

  • 5 篇 Markdown109 个静态文件
  • 首次构建部署 ~50 秒(GitHub Actions)
  • 写完笔记 git push 后约 1 分钟网站自动更新
  • 暗色模式自动跟随系统偏好
  • 双向链接、关系图谱、搜索、目录导航全部开箱即用