[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"chapter-post-project-replication-guide-05-preview-tunnel-and-access":3},{"chapter":4,"entry":73,"prev":214,"next":350},{"id":5,"title":6,"body":7,"category":55,"cover":52,"date":56,"description":57,"draft":58,"extension":59,"lang":60,"meta":61,"navigation":62,"path":63,"seo":64,"slug":65,"stem":66,"tags":67,"toc":62,"updated":56,"__hash__":72},"chapters/chapters/project-replication-guide.md","零基础完整复刻：Cloudflare 博客项目全流程",{"type":8,"value":9,"toc":51},"minimark",[10,14,17,30,33,45,48],[11,12,13],"p",{},"这个章节是你当前博客项目的“完整复刻手册”。",[11,15,16],{},"目标读者：",[18,19,20,24,27],"ul",{},[21,22,23],"li",{},"没有代码基础",[21,25,26],{},"第一次接触 GitHub、Cloudflare、Nuxt、Decap CMS",[21,28,29],{},"希望照着文档一步步做，最终得到与你当前项目一致的结果",[11,31,32],{},"学习方式建议：",[34,35,36,39,42],"ol",{},[21,37,38],{},"严格按顺序学习，不要跳步骤",[21,40,41],{},"每做完一节就执行“本节验收”",[21,43,44],{},"发现报错先看“常见问题”再继续",[11,46,47],{},"你可以直接从下面目录开始：",[49,50],"chapter-children",{},{"title":52,"searchDepth":53,"depth":53,"links":54},"",2,[],"Chapter","2026-02-14","面向零基础读者的完整项目复刻章节：从准备账号、搭建 Nuxt，到 Pages、Tunnel、CMS、评论、夜间模式与排障。",false,"md","zh-CN",{},true,"/chapters/project-replication-guide",{"title":6,"description":57},"project-replication-guide","chapters/project-replication-guide",[68,69,70,71],"复刻教程","Cloudflare","Nuxt","零基础","T31gU2a4Q3CvJ3Z2B2jyDvX4BtLMmICHnwzpIIudkao",{"id":74,"title":75,"body":76,"category":201,"chapterSlug":65,"cover":52,"date":56,"description":202,"draft":58,"extension":59,"lang":60,"legacySlugs":203,"meta":204,"navigation":62,"order":205,"path":206,"seo":207,"slug":208,"stem":209,"tags":210,"toc":62,"updated":56,"__hash__":213},"chapterPosts/chapter-posts/project-replication-guide/05-preview-tunnel-and-access.md","第 5 节：预览链路（Cloudflare Tunnel + Access）",{"type":8,"value":77,"toc":194},[78,83,86,106,110,113,127,130,134,137,140,148,152,155,158,169,173,176],[79,80,82],"h2",{"id":81},"_51-架构目标","5.1 架构目标",[11,84,85],{},"你要达到下面 2 条：",[34,87,88,96],{},[21,89,90,91,95],{},"主站永远公开可用（",[92,93,94],"code",{},"www","）",[21,97,98,99,102,103,95],{},"预览与运维私有访问（",[92,100,101],{},"preview"," / ",[92,104,105],{},"ops",[79,107,109],{"id":108},"_52-草稿显示机制","5.2 草稿显示机制",[11,111,112],{},"通过变量控制：",[18,114,115,121],{},[21,116,117,118],{},"Production：",[92,119,120],{},"NUXT_PUBLIC_SHOW_DRAFTS=false",[21,122,123,124],{},"Preview：",[92,125,126],{},"NUXT_PUBLIC_SHOW_DRAFTS=true",[11,128,129],{},"这样同一套代码在不同环境会得到不同可见性。",[79,131,133],{"id":132},"_53-tunnel-的职责","5.3 Tunnel 的职责",[11,135,136],{},"Tunnel 不是托管主站内容，而是把本地预览服务安全暴露出去。",[11,138,139],{},"典型用途：",[18,141,142,145],{},[21,143,144],{},"草稿内容预览",[21,146,147],{},"私有后台入口",[79,149,151],{"id":150},"_54-access-的职责","5.4 Access 的职责",[11,153,154],{},"Access 是“谁能进来”的门禁系统。",[11,156,157],{},"你应配置：",[34,159,160,163,166],{},[21,161,162],{},"只允许你的邮箱登录",[21,164,165],{},"会话有效期缩短（例如 1~8 小时）",[21,167,168],{},"打开审计日志",[79,170,172],{"id":171},"_55-验收测试","5.5 验收测试",[11,174,175],{},"必须做这 3 条：",[34,177,178,184,191],{},[21,179,180,181,183],{},"关闭本地 Tunnel 后，",[92,182,94],{}," 仍能访问。",[21,185,186,187,190],{},"未授权访问 ",[92,188,189],{},"preview.*","，看到拦截页。",[21,192,193],{},"授权后能访问预览站，并看到草稿。",{"title":52,"searchDepth":53,"depth":53,"links":195},[196,197,198,199,200],{"id":81,"depth":53,"text":82},{"id":108,"depth":53,"text":109},{"id":132,"depth":53,"text":133},{"id":150,"depth":53,"text":151},{"id":171,"depth":53,"text":172},"Guide","把草稿预览和后台放到私有入口，确保 Tunnel 失效不影响公开主站。",[],{},5,"/chapter-posts/project-replication-guide/05-preview-tunnel-and-access",{"title":75,"description":202},"05-preview-tunnel-and-access","chapter-posts/project-replication-guide/05-preview-tunnel-and-access",[68,211,212],"Tunnel","Zero Trust","xw4xbvKHiLSWUi6NwiRDw5FtQ_GiERPmprH3_HLe6fU",{"id":215,"title":216,"body":217,"category":201,"chapterSlug":65,"cover":52,"date":56,"description":338,"draft":58,"extension":59,"lang":60,"legacySlugs":339,"meta":340,"navigation":62,"order":341,"path":342,"seo":343,"slug":344,"stem":345,"tags":346,"toc":62,"updated":56,"__hash__":349},"chapterPosts/chapter-posts/project-replication-guide/04-domain-dns-and-redirect.md","第 4 节：域名、DNS 与 301 跳转（主域统一）",{"type":8,"value":218,"toc":332},[219,223,226,229,240,244,247,273,279,283,286,289,300,304,307,314,317,325],[79,220,222],{"id":221},"_41-为什么要做裸域-301-到-www","4.1 为什么要做裸域 301 到 www",[11,224,225],{},"统一主域可以减少 SEO 分裂和链接重复。",[11,227,228],{},"你的目标是：",[18,230,231],{},[21,232,233,236,237],{},[92,234,235],{},"https://xuyangfly.site/xxx"," 永久跳到 ",[92,238,239],{},"https://www.xuyangfly.site/xxx",[79,241,243],{"id":242},"_42-跳转规则怎么填","4.2 跳转规则怎么填",[11,245,246],{},"在 Cloudflare 中创建转发规则：",[34,248,249,255,261,267],{},[21,250,251,252],{},"URL 匹配：",[92,253,254],{},"xuyangfly.site/*",[21,256,257,258],{},"类型：",[92,259,260],{},"Forwarding URL",[21,262,263,264],{},"状态码：",[92,265,266],{},"301 - Permanent Redirect",[21,268,269,270],{},"目标：",[92,271,272],{},"https://www.xuyangfly.site/$1",[11,274,275,278],{},[92,276,277],{},"$1"," 代表原路径后半段，会被完整保留。",[79,280,282],{"id":281},"_43-为什么你会看到rule-may-not-apply-to-traffic","4.3 为什么你会看到“rule may not apply to traffic”",[11,284,285],{},"这提示表示：当前流量没走 Cloudflare 代理层。",[11,287,288],{},"修复：",[34,290,291,294,297],{},[21,292,293],{},"到 DNS 列表确认根域记录是橙云（Proxied）",[21,295,296],{},"如果没有合适记录，创建一个 A 记录占位并开启代理",[21,298,299],{},"保存后等待 1~5 分钟再测",[79,301,303],{"id":302},"_44-验证命令","4.4 验证命令",[11,305,306],{},"在浏览器访问：",[18,308,309],{},[21,310,311],{},[92,312,313],{},"https://xuyangfly.site/test?a=1",[11,315,316],{},"期望：",[18,318,319],{},[21,320,321,322],{},"地址栏最终变成 ",[92,323,324],{},"https://www.xuyangfly.site/test?a=1",[11,326,327,328,331],{},"如果是连接失败（如 ",[92,329,330],{},"ERR_CONNECTION_CLOSED","），优先回到 DNS 检查代理状态。",{"title":52,"searchDepth":53,"depth":53,"links":333},[334,335,336,337],{"id":221,"depth":53,"text":222},{"id":242,"depth":53,"text":243},{"id":281,"depth":53,"text":282},{"id":302,"depth":53,"text":303},"把裸域 xuyangfly.site 301 到 www，解决规则不生效与代理记录问题。",[],{},4,"/chapter-posts/project-replication-guide/04-domain-dns-and-redirect",{"title":216,"description":338},"04-domain-dns-and-redirect","chapter-posts/project-replication-guide/04-domain-dns-and-redirect",[68,347,348],"DNS",301,"578oUC4KJGN4YYl6zTyB-MLXMLtuDPxHNbfKQbOntiI",{"id":351,"title":352,"body":353,"category":201,"chapterSlug":65,"cover":52,"date":56,"description":651,"draft":58,"extension":59,"lang":60,"legacySlugs":652,"meta":653,"navigation":62,"order":464,"path":654,"seo":655,"slug":656,"stem":657,"tags":658,"toc":62,"updated":56,"__hash__":662},"chapterPosts/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker.md","第 6 节：Decap CMS 与 GitHub OAuth Worker",{"type":8,"value":354,"toc":643},[355,359,366,369,386,389,393,398,473,477,483,500,503,541,552,556,562,576,579,583,615,618,622,639],[79,356,358],{"id":357},"_61-为什么要单独部署-oauth-worker","6.1 为什么要单独部署 OAuth Worker",[11,360,361,362,365],{},"你遇到过默认 Netlify OAuth 回调不可用问题（",[92,363,364],{},"Not Found","）。",[11,367,368],{},"因此项目采用自建方案：",[18,370,371,377],{},[21,372,373,376],{},[92,374,375],{},"ops/decap-oauth/worker.js"," 处理 GitHub OAuth",[21,378,379,382,383],{},[92,380,381],{},"public/admin/config.yml"," 指向你自己的 ",[92,384,385],{},"base_url",[11,387,388],{},"这让登录链路完全可控。",[79,390,392],{"id":391},"_62-cms-配置必须与项目一致","6.2 CMS 配置（必须与项目一致）",[11,394,395,397],{},[92,396,381],{}," 核心段：",[399,400,404],"pre",{"className":401,"code":402,"language":403,"meta":52,"style":52},"language-yaml shiki shiki-themes github-light github-dark","backend:\n  name: github\n  repo: adkeb/blog\n  branch: main\n  base_url: https://decap-github-oauth.xuyang020128.workers.dev\n  auth_endpoint: auth\n","yaml",[92,405,406,419,431,442,452,462],{"__ignoreMap":52},[407,408,411,415],"span",{"class":409,"line":410},"line",1,[407,412,414],{"class":413},"s9eBZ","backend",[407,416,418],{"class":417},"sVt8B",":\n",[407,420,421,424,427],{"class":409,"line":53},[407,422,423],{"class":413},"  name",[407,425,426],{"class":417},": ",[407,428,430],{"class":429},"sZZnC","github\n",[407,432,434,437,439],{"class":409,"line":433},3,[407,435,436],{"class":413},"  repo",[407,438,426],{"class":417},[407,440,441],{"class":429},"adkeb/blog\n",[407,443,444,447,449],{"class":409,"line":341},[407,445,446],{"class":413},"  branch",[407,448,426],{"class":417},[407,450,451],{"class":429},"main\n",[407,453,454,457,459],{"class":409,"line":205},[407,455,456],{"class":413},"  base_url",[407,458,426],{"class":417},[407,460,461],{"class":429},"https://decap-github-oauth.xuyang020128.workers.dev\n",[407,463,465,468,470],{"class":409,"line":464},6,[407,466,467],{"class":413},"  auth_endpoint",[407,469,426],{"class":417},[407,471,472],{"class":429},"auth\n",[79,474,476],{"id":475},"_63-worker-环境变量与密钥","6.3 Worker 环境变量与密钥",[11,478,479,482],{},[92,480,481],{},"ops/decap-oauth/wrangler.toml"," 里是公开配置：",[18,484,485,490,495],{},[21,486,487],{},[92,488,489],{},"CMS_ORIGIN",[21,491,492],{},[92,493,494],{},"GITHUB_REDIRECT_URI",[21,496,497],{},[92,498,499],{},"GITHUB_CLIENT_ID",[11,501,502],{},"密钥必须用 secret：",[399,504,508],{"className":505,"code":506,"language":507,"meta":52,"style":52},"language-bash shiki shiki-themes github-light github-dark","npx wrangler secret put GITHUB_CLIENT_SECRET\nnpx wrangler secret put OAUTH_STATE_SECRET\n","bash",[92,509,510,528],{"__ignoreMap":52},[407,511,512,516,519,522,525],{"class":409,"line":410},[407,513,515],{"class":514},"sScJk","npx",[407,517,518],{"class":429}," wrangler",[407,520,521],{"class":429}," secret",[407,523,524],{"class":429}," put",[407,526,527],{"class":429}," GITHUB_CLIENT_SECRET\n",[407,529,530,532,534,536,538],{"class":409,"line":53},[407,531,515],{"class":514},[407,533,518],{"class":429},[407,535,521],{"class":429},[407,537,524],{"class":429},[407,539,540],{"class":429}," OAUTH_STATE_SECRET\n",[11,542,543,547,548,551],{},[544,545,546],"strong",{},"注意","：",[92,549,550],{},"GITHUB_CLIENT_SECRET"," 绝对不能写入 git。",[79,553,555],{"id":554},"_64-worker-路由逻辑读懂就够不用会写","6.4 Worker 路由逻辑（读懂就够，不用会写）",[11,557,558,561],{},[92,559,560],{},"worker.js"," 做两件事：",[34,563,564,570],{},[21,565,566,569],{},[92,567,568],{},"/auth","：发起 GitHub 授权",[21,571,572,575],{},[92,573,574],{},"/callback","：换 token 并回传给 Decap 窗口",[11,577,578],{},"你项目中还做了弹窗握手与 postMessage 回传，解决了“登录成功但 CMS 不更新”的常见问题。",[79,580,582],{"id":581},"_65-部署命令完整","6.5 部署命令（完整）",[399,584,586],{"className":505,"code":585,"language":507,"meta":52,"style":52},"cd ops/decap-oauth\nnpx wrangler whoami\nnpx wrangler deploy\n",[92,587,588,597,606],{"__ignoreMap":52},[407,589,590,594],{"class":409,"line":410},[407,591,593],{"class":592},"sj4cs","cd",[407,595,596],{"class":429}," ops/decap-oauth\n",[407,598,599,601,603],{"class":409,"line":53},[407,600,515],{"class":514},[407,602,518],{"class":429},[407,604,605],{"class":429}," whoami\n",[407,607,608,610,612],{"class":409,"line":433},[407,609,515],{"class":514},[407,611,518],{"class":429},[407,613,614],{"class":429}," deploy\n",[11,616,617],{},"部署成功会返回你的 workers.dev 地址。",[79,619,621],{"id":620},"_66-验收标准","6.6 验收标准",[34,623,624,630,633,636],{},[21,625,626,627],{},"打开 ",[92,628,629],{},"https://www.xuyangfly.site/admin",[21,631,632],{},"点“使用 GitHub 登录”",[21,634,635],{},"授权后可进入 CMS 内容列表",[21,637,638],{},"新建文章后能触发 Git 提交",[640,641,642],"style",{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":52,"searchDepth":53,"depth":53,"links":644},[645,646,647,648,649,650],{"id":357,"depth":53,"text":358},{"id":391,"depth":53,"text":392},{"id":475,"depth":53,"text":476},{"id":554,"depth":53,"text":555},{"id":581,"depth":53,"text":582},{"id":620,"depth":53,"text":621},"从 Netlify 失败场景迁移到 Cloudflare Worker OAuth 网关，打通 /admin 可视化编辑。",[],{},"/chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",{"title":352,"description":651},"06-decap-cms-and-oauth-worker","chapter-posts/project-replication-guide/06-decap-cms-and-oauth-worker",[68,659,660,661],"Decap CMS","OAuth","Worker","CftJ87f8FswywDArDHUTg3sgFZwMb6KyNdd-iw7FgN8",1771232916065]