Obsidian 笔记发布 — Quartz + CF Pages + Zero Trust
TL;DR
Obsidian 笔记通过 Quartz 生成静态网站,部署到 Cloudflare Pages,用 Zero Trust Access 做邮箱白名单验证。GitHub 私有仓库存储源文件,改完笔记跑
bash sync.sh一键同步。老师浏览器打开notes.getgrowth.app,邮箱验证后直接看笔记。现状:✅ 已跑通,
notes.getgrowth.app正常访问。
🎯 背景:为什么需要这个
- 需求:把 Obsidian 笔记分享给老师看,但不能把 50+ 个 .md 文件直接发过去——太多、不好传、没有导航和搜索
- 约束:笔记不能公开,只能特定人能看;不能花钱(CF Pages 免费额度内搞定)
- 被否决的方案:Obsidian Publish($8/月,每次发布手动操作)、直接发 .md 文件(老师没法浏览双链和 Mermaid 图)
✅ 前置条件
跑这篇笔记之前,你手上应该已经有:
- Obsidian vault(笔记已经在里面)
- GitHub 账号 + 已安装
ghCLI 并登录 - Cloudflare 托管域名(
getgrowth.app) - Node.js ≥ v20(本机 v24 验证通过)
- WSL2 环境(Windows)
🏗️ 最终架构
Obsidian 写笔记 (本地 vault)
│ bash sync.sh
▼
rsync 复制到 ~/quartz-site/content/
│ npx quartz build
▼
生成 public/ (HTML)
│ git push
▼
GitHub 私有仓库 (miaoQ777/knowledge-base)
│ CF Pages 检测到 push,自动构建
▼
Cloudflare Pages (全球 CDN)
│ Zero Trust Access 拦截
▼
邮箱验证页 → 白名单通过 → notes.getgrowth.app
和”一开始想的软链接方案”比,省了 CF 构建时找不到本地 vault 的坑(404)。笔记真实存入 Git 仓库,CF 能正常克隆和构建。
🛠️ 部署步骤
关于这部分的阅读方式
每一步先给”抄了就能跑”的命令,命令下面折叠的 Callout 是详细解释——不想看原理的话,跳过折叠框直接抄下一条命令即可。
第 1 步:克隆 Quartz v4
cd ~
git clone --branch v4 --depth 1 https://github.com/jackyzha0/quartz.git quartz-site
cd quartz-site
npm install这条命令在干嘛(点击展开)
Quartz 是开源的 Obsidian 静态网站生成器。选 v4 而不是 v5——v5 刚发布,Node v24 下
.scss编译报错(ERR_UNKNOWN_FILE_EXTENSION),v4 稳定运行两年,Node 20/22/24 全兼容。--depth 1只克隆最新版本,体积小、速度快。
第 2 步:配置 quartz.config.ts
编辑 ~/quartz-site/quartz.config.ts,改以下字段:
pageTitle: "Growth App 知识库",
locale: "zh-CN",
baseUrl: "notes.getgrowth.app",
ignorePatterns: ["private", "templates", ".obsidian", "账号", "*.excalidraw"],
analytics: null,这条命令在干嘛(点击展开)
ignorePatterns在构建时排除不想公开的目录和文件。analytics: null关闭流量统计(不想给第三方泄露访问数据)。locale: "zh-CN"让日期格式和界面文字显示中文。
第 3 步:初始化 content 目录
cd ~/quartz-site
mkdir -p content先不用 rsync,等写完 sync.sh 再同步。先在 vault 根目录创建首页:
/mnt/e/KnowledgeBase/index.md:
---
title: Growth App 知识库
---
# Growth App 主权架构知识库
欢迎。
## 入口
- [[主权架构/最新架构]] — 当前基础设施架构
- [[press/维护]] — Press 日常运维
## 目录
- **主权架构** — 架构设计与演化
- **press** — Frappe Press 部署与运维
- **Cloudflare** — CF 各项功能这条命令在干嘛(点击展开)
Quartz 需要一个
index.md作为网站首页,否则构建时警告。首页相当于网站导航页,列出关键入口。
第 4 步:创建同步脚本
~/quartz-site/sync.sh:
#!/bin/bash
set -e
source ~/.nvm/nvm.sh
nvm use 24
echo "=== 同步笔记 ==="
rsync -a \
--exclude='.obsidian/' --exclude='.git/' \
--exclude='*.excalidraw' --exclude='账号.md' --exclude='*.canvas' \
/mnt/e/KnowledgeBase/ content/
echo "=== 构建 ==="
npx quartz build
echo "=== 推送 ==="
git add -A
git commit -m "sync: $(date +%Y-%m-%d)" || echo "无新内容"
git push
echo "=== 完成: https://notes.getgrowth.app ==="chmod +x ~/quartz-site/sync.sh
bash ~/quartz-site/sync.sh这条命令在干嘛(点击展开)
rsync -a保留文件权限和时间戳。--exclude排除敏感文件——账号.md含密码不能进仓库,.excalidraw是 Excalidraw 专用格式 Quartz 无法渲染,.obsidian是插件配置不需要发布。npx quartz build把 Markdown 编译成 HTML。git push推到 GitHub,CF Pages 自动检测并重新部署。|| echo "无新内容"防止没有改动时 git commit 报错中断脚本。
第 5 步:创建 GitHub 私有仓库并推送
cd ~/quartz-site
gh repo create miaoQ777/knowledge-base --private --source=. --remote=origin --push这条命令在干嘛(点击展开)
--private保证仓库只有你和你添加的 collaborator 能访问。--source=.用当前目录作为仓库内容。
第 6 步:Cloudflare Pages 连接 GitHub
- dash.cloudflare.com → Workers & Pages → Create → Pages → Connect to Git
- 授权 GitHub → 选
miaoQ777/knowledge-base
构建设置:
| 字段 | 值 |
|---|---|
| Production branch | main |
| Build command | npx quartz build |
| Build output directory | public |
环境变量:
| 变量 | 值 |
|---|---|
NODE_VERSION | 22 |
这条命令在干嘛(点击展开)
Pages 和 Workers 是两个不同的产品。如果看到”部署命令”、“API 令牌”、“wrangler”等字段——说明走错了,那是 Workers 的页面。Pages 只需要构建命令和输出目录。
NODE_VERSION=22是因为 CF Pages 构建环境可能还没默认 Node 24,22 是它支持的最新 LTS。
第 7 步:Cloudflare Zero Trust 邮箱验证
- Cloudflare Dashboard → Zero Trust → Access → Applications → Add an application
- 选 Self-hosted(中文可能叫”私人目的地”)
- 填 subdomain:
notes,domain:getgrowth.app,Path 留空 - 点 Create → 进入刚创建的应用 → Policies 标签 → Create new policy
- Policy name:
Allowed,Action:Allow - Add Rule → Include → Emails → 填老师和自己的邮箱
- 所有开关(MFA、Purpose justification、Temporary auth)全关着不动
- Save policy
这条命令在干嘛(点击展开)
Zero Trust Access 在 DNS 层拦截所有到
notes.getgrowth.app的请求。白名单里的邮箱收到一次性验证码,通过后才放行。50 人以内完全免费。
第 8 步:绑自定义域名
Pages 项目 → Custom domains → Set up a custom domain → 填 notes.getgrowth.app → Continue → Activate domain。
这条命令在干嘛(点击展开)
你已有
*.getgrowth.app通配符 A 记录指向 n1。CF 自动添加一条 CNAMEnotes.getgrowth.app → knowledge-base-xxx.pages.dev,优先级高于通配符,只覆盖notes这一个子域名。其他子域名不受影响。
↩️ 回滚 / 卸载
- 停止网站:CF Pages → 项目 Settings → Delete project(源文件和 GitHub 仓库不受影响)
- 去掉邮箱验证:Zero Trust → Access → Applications → 删除
KnowledgeBase应用 - 清理本机:
rm -rf ~/quartz-site - 清理 GitHub:
gh repo delete miaoQ777/knowledge-base - 回滚后验证:
notes.getgrowth.app不再解析或返回 CF 错误页
🔍 验证方法
# 1. 本地构建成功
cd ~/quartz-site && npx quartz build
# → Done processing 54 files in Xs
# 2. 网站可访问
curl -s -o /dev/null -w "%{http_code}" https://notes.getgrowth.app
# → 不应返回 200(被 Zero Trust 拦截,返回 CF 登录页,状态码 302 或 403)
# 3. 邮箱验证后可访问(浏览器测试)
# 打开 https://notes.getgrowth.app → 输入邮箱 → 收到验证码 → 进入笔记首页如果 curl 返回 404 → CF Pages 构建失败或 content 目录为空(见故障排查 #1)。
🧠 涉及到的代码逻辑
| 文件 | 做了什么 |
|---|---|
~/quartz-site/quartz.config.ts | Quartz 配置:标题、语言、排除目录、域名 |
~/quartz-site/sync.sh | 一键同步脚本:rsync → build → git push |
~/quartz-site/.gitignore | 排除 node_modules、public、.quartz 不进仓库 |
/mnt/e/KnowledgeBase/index.md | 网站首页 |
流程简述:
- 用户在 Obsidian 写笔记 → vault 文件更新
bash sync.sh→ rsync 复制到content/(排除敏感文件)npx quartz build→ Markdown 编译为public/目录的 HTMLgit push→ 推到 GitHub 私有仓库- CF Pages 检测到 push → 自动 clone →
npx quartz build→ 部署到 CDN - 用户访问
notes.getgrowth.app→ Zero Trust 拦截 → 邮箱验证 → 放行
关键细节(如果只说一件事):CF Pages 构建环境没有你的本地 vault。软链接方案在 CF 上会 404,必须把笔记真实文件存入仓库。
💡 总结经验
- 这次最大的教训:软链接在本地能工作,在 CI/CD 环境里就是空目录。先本地验证再推送到远程构建的步骤不能省
- 如果再来一次,我会先测试 CF Pages 的构建环境能不能访问我的文件,而不是直接把软链接推上去然后看到 404
- 这个问题的本质其实是”构建环境和开发环境不一致”,不是 Quartz 或 CF 的 bug
- 以后排查类似问题,第一时间应该看的三个东西:1) CF Pages 构建日志 2) content 目录是否为空 3)
public/是否生成成功
🕳️ 踩过的坑 & 被否决的方案
方案 A:content 用软链接指向 vault(已否决)
问题:本地构建正常,推到 GitHub 后 CF Pages 构建出来是空网站(404) 证据:
content -> /mnt/e/KnowledgeBase是绝对路径软链接,CF 构建环境是 Linux 容器,没有/mnt/e/教训:永远不要假设远程 CI 环境有和你本机一样的文件路径
方案 B:Quartz v5(已否决)
问题:Node v24 下安装社区插件时报
ERR_UNKNOWN_FILE_EXTENSION,.scss文件无法编译 证据:TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".scss"教训:新主版本(v5 2026 年刚发布)先在本机跑通再采用,不要在生产部署中尝鲜
方案 C:纯软链接 + 本机构建 + wrangler 直接部署(已否决)
问题:需要本机一直在线、占用本机资源、增加 wrangler 依赖 教训:GitHub 私有仓库方案更轻量,部署完全托管在 CF
坑 1:VPN 全局模式导致 git clone 失败
现象:
error: RPC failed; curl 56 GnuTLS recv error根因:VPN 全局模式劫持 DNS,github.com 被解析到198.18.0.14(IANA 保留测试网段),VPN 代理做 TLS 中间人拦截时握手失败 解决:关 VPN,直连 GitHub
坑 2:CF Pages 和 Workers 创建页面搞混
现象:创建页面出现”部署命令”、“wrangler”、“API 令牌”等字段 根因:点进了 Workers 而非 Pages 解决:路径是 Workers & Pages → Create → Pages → Connect to Git(不是 Workers)
坑 3:node_modules 被意外提交到 Git
现象:push 失败
remote unpack failed: index-pack failed根因:.gitignore没写好,几千个node_modules文件被git add -A包含 解决:写好.gitignore,rm -rf .git && git init重新提交
坑 4:Node v22 安装后又卸载
现象:以为 Quartz 需要 Node 22(v24 下 Quartz v5 报错了),后来发现 Quartz v4 在 v24 完全正常 根因:v5 的
.scss报错误导判断,以为是 Node 版本问题 解决:切回 v4,删 v22,只用 v24
🩺 故障排查决策树
症状 1:notes.getgrowth.app 返回 404
→ 查 CF Pages 构建日志(Dashboard → Pages → knowledge-base → Deployments)
→ 如果是 "content/index.md not found" → content 目录是空的,检查 sync.sh 是否成功运行
→ 如果是构建命令失败 → 检查 quartz.config.ts 语法
症状 2:sync.sh 报错
→ npx quartz build 失败 → 检查 Node 版本(需要 ≥20)
→ rsync 报权限错误 → 检查 /mnt/e/KnowledgeBase 是否可访问
→ git push 报认证错误 → 运行 gh auth status
症状 3:邮箱验证后页面白屏
→ 浏览器 F12 → Network 标签 → 看哪个资源加载失败
→ CSS/JS 404 → CF Pages 构建不完整,重新 push 触发构建
→ 所有资源正常但页面空白 → quartz.config.ts 的 baseUrl 配置错误
⚠️ 已知限制 / 副作用
- 每次改完笔记要手动跑 sync.sh。不像 Obsidian Publish 一键发布。但一行命令的成本可以接受
- Excalidraw 文件被排除(
*.excalidraw),如果以后想发布 Excalidraw 图,需要先导出 PNG 再嵌入笔记 - LaTeX 数学公式里不能有中文。中文出现在
$...$里会触发警告(不影响构建,但渲染可能异常) - GitHub 私有仓库源文件对平台运维人员理论上可见。真正的商业机密(密钥、合同、客户数据)不建议放
- CF Zero Trust 保护的是域名访问层。如果有人在 CDN 节点层面直接访问构建产物,理论上能绕过邮箱验证
🚨 监控 / 告警
- 健康检查:
curl -s -o /dev/null -w "%{http_code}" https://notes.getgrowth.app→ 返回 302/403 说明 Zero Trust 在线;返回 200 说明 Zero Trust 掉了(立刻查) - CF Pages 构建失败:GitHub push 后等 1-2 分钟,去 CF Dashboard → Pages → knowledge-base → Deployments 看状态。CF 不会主动通知你构建失败
- 如果彻底挂了:CF 或 GitHub 宕机(概率极低)。恢复后 push 一次即可触发重新构建
🔒 安全 & 成本速查
- 密钥/Token:GitHub OAuth Token(
gh auth管理),CF Deploy Token(自动生成,Dashboard 可见)。权限:GitHub→仓库读写,CF→Pages 部署 - 谁能访问:GitHub 仓库:你 + collaborator;网站:Zero Trust 邮箱白名单
- 月度成本:$0(CF Pages 免费:无限站点/请求/带宽,每月 500 次构建;GitHub 免费:无限私有仓库;Zero Trust:50 用户免费)
- 如果要下线:CF Pages → 删项目;Zero Trust → 删 Access 应用;GitHub → 删仓库
📌 待办 / 未来优化方向
- 给 sync.sh 加自动触发:Obsidian 保存文件时自动同步(用
inotifywait监听 vault 目录变化) - 考虑在笔记 frontmatter 里加
publish: true/false控制是否发布(Quartz v4 的RemoveDrafts插件支持) - 老师如果想编辑笔记:给他 GitHub collaborator 权限 + 装 Obsidian,克隆仓库后在本地 Obsidian 打开
📋 速查命令合集(复制专用,无解释)
# 日常发布笔记
bash ~/quartz-site/sync.sh
# 本地预览(http://localhost:8080)
source ~/.nvm/nvm.sh && nvm use 24 && cd ~/quartz-site && npx quartz build --serve
# 查看构建日志
gh browse -R miaoQ777/knowledge-base
# 检查网站状态
curl -s -o /dev/null -w "%{http_code}" https://notes.getgrowth.app📝 更新日志
| 日期 | 改动 | 原因 |
|---|---|---|
| 2026-07-13 | 首次创建,全流程跑通 | — |