目标很朴素:一次 git push,三端全部自动更新,国内用户走 Gitee、海外用户走 GitHub / Cloudflare,谁都能打开官网。这篇记录完整的落地过程与踩过的坑。
整体架构
| 端 | 地址 | 职责 |
|---|---|---|
| 主域(GitHub Pages) | gjsvip.github.io | 官网唯一主入口,国内外可达,干净无路径 |
| Cloudflare Workers | dujiecode.dujie-nb.workers.dev | 完整版:API + 静态资源,边缘直服,不做跳转 |
| Cloudflare Pages | dujiecode.pages.dev | 静态镜像 + 备用入口 |
| Gitee 镜像 | dujie_nb_admin.gitee.io/dujiecode/ | 国内加速镜像 |
| 代码仓库 | GitHub + Gitee 双库 | 双向可访问,Issue 集中 |
工作流拆分
deploy.yml 负责部署,mirror-to-gitee.yml 负责镜像,互不阻塞:
push to main
├─ deploy.yml
│ ├─ build & test(tsc + vitest 64 项)
│ ├─ D1 幂等初始化
│ ├─ wrangler deploy → Cloudflare Workers
│ ├─ wrangler pages deploy → Cloudflare Pages
│ └─ peaceiris/actions-gh-pages → gjsvip.github.io 主域
└─ mirror-to-gitee.yml
└─ git push --mirror → Gitee(main + tags)
踩坑记录
1. peaceiris 跨仓库部署必须用 personal_token
最初给 github_token 传入 PAT,action 直接报错「does not support to push to an external repository」。读源码发现:github_token 输入仅用于同仓库,跨 external_repository 必须用 personal_token 或 deploy_key。
2. Gitee 拒绝 --mirror 推送
deny updating a hidden ref——镜像前先 git remote remove origin,只推 refs/heads/* 与 tags 即可。
3. Job 级 if: secrets.X 导致零任务静默失败
密钥缺失时整个 job 不生成任务、不报错。改为步骤内 shell 判断,缺失时明确打印提示。
4. 主域与博客的目录冲突
官网主域要「不带 /」的干净地址,博客又要在同一域名下。最终方案:官网占根路径,博客独立仓库 gjsvip/blog 以项目页形式挂载到 /blog/,两套 Pages 构建互不覆盖。
国内外可达性
国内网络对 workers.dev 与 pages.dev 的 SNI 时有干扰,因此:
- 主域 gjsvip.github.io 由 GitHub Pages 承载,国内直连稳定,作为唯一主入口
- Gitee Pages 镜像作为国内加速备份
- Cloudflare Workers 侧移除地域跳转,任何访客直达服务,国内访客仅在落地页顶部看到镜像推荐条(软提示,不强制)
收录(SEO)
robots.txt使用相对路径 Sitemap 指令,各托管端各自解析sitemap.xml覆盖主域各页、博客三篇文章、workers.dev 与 pages.dev- 通过 IndexNow 协议主动推送收录(key 托管于主域根路径)
小结
三端同步的核心是「职责分离」:GitHub Actions 管部署,Gitee 只做代码与 Pages 镜像,Cloudflare 管边缘运行时。一次推送,全链路生效——剩下的,交给自动化。