<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hugo on zouyiyi 的技术笔记</title><link>https://blog.zouyiyi.top/tags/hugo/</link><description>Recent content in Hugo on zouyiyi 的技术笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Fri, 13 Nov 2026 01:01:00 +0800</lastBuildDate><atom:link href="https://blog.zouyiyi.top/tags/hugo/index.xml" rel="self" type="application/rss+xml"/><item><title>从购买域名到自动发布：我的 Cloudflare 技术博客搭建记录</title><link>https://blog.zouyiyi.top/posts/domain-to-cloudflare-blog/</link><pubDate>Fri, 13 Nov 2026 01:01:00 +0800</pubDate><guid>https://blog.zouyiyi.top/posts/domain-to-cloudflare-blog/</guid><description>&lt;img src="https://blog.zouyiyi.top/posts/domain-to-cloudflare-blog/cover.svg" alt="Featured image of post 从购买域名到自动发布：我的 Cloudflare 技术博客搭建记录" /&gt;&lt;p&gt;我想搭一个用来记录技术学习和成长的博客：有自己的域名，首页能展示图片，文章按时间和标签整理；平时可以在网页里写，也可以把想法交给 agent，让它整理成 Markdown 后发布。&lt;/p&gt;&#10;&lt;p&gt;刚开始，我并没有完全分清域名、DNS、服务器和托管平台的关系。买到 &lt;code&gt;zouyiyi.top&lt;/code&gt; 后，我先后问过：域名到底怎么用？Cloudflare 会分配一台服务器吗？没有公网 IP 怎么放博客？&lt;code&gt;blog.zouyiyi.top&lt;/code&gt; 和 &lt;code&gt;api.zouyiyi.top&lt;/code&gt; 是不是还要再买？&lt;/p&gt;&#10;&lt;p&gt;这篇文章记录这次实际搭建的路径，以及后来“后台已经发布，前台却没更新”“点开文章是 404”的排查过程。最终使用的是 &lt;strong&gt;Cloudflare Workers Static Assets&lt;/strong&gt; 托管博客，&lt;strong&gt;Workers Builds&lt;/strong&gt; 自动构建；没有租一台需要自己维护的 VPS。&lt;/p&gt;&#10;&lt;h2 id="先看最终结构每个服务负责什么"&gt;&lt;a href="#%e5%85%88%e7%9c%8b%e6%9c%80%e7%bb%88%e7%bb%93%e6%9e%84%e6%af%8f%e4%b8%aa%e6%9c%8d%e5%8a%a1%e8%b4%9f%e8%b4%a3%e4%bb%80%e4%b9%88" class="header-anchor"&gt;&lt;/a&gt;先看最终结构：每个服务负责什么&#10;&lt;/h2&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;组件&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;本次负责的事情&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;NameSilo&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;域名注册和续费管理&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloudflare DNS&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;管理 &lt;code&gt;zouyiyi.top&lt;/code&gt; 的 DNS 解析&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Hugo + Stack&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;把 Markdown 和图片生成静态网站&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;GitHub 私有仓库&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;保存文章、图片、主题配置和版本历史&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Decap CMS&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;提供浏览器里的文章编辑界面&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;独立的登录 Worker&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;完成 GitHub 登录回调，检查站点所有者身份&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloudflare Workers Builds&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;监听生产分支，自动构建并部署&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloudflare Workers Static Assets&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;向读者提供生成后的 HTML、CSS、JavaScript 和图片&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;img alt="域名解析、两种写作入口和 Cloudflare 自动发布的关系" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.zouyiyi.top/posts/domain-to-cloudflare-blog/architecture.svg"&gt;&lt;/p&gt;&#10;&lt;p&gt;这里有两条不同的链路：读者通过域名访问已经生成的网站；作者通过 Git 修改源文件，再让构建系统更新网站。写作时使用的编辑器可以变化，最终都汇入同一个仓库。&lt;/p&gt;&#10;&lt;h2 id="1-买域名注册商与网站托管可以分开"&gt;&lt;a href="#1-%e4%b9%b0%e5%9f%9f%e5%90%8d%e6%b3%a8%e5%86%8c%e5%95%86%e4%b8%8e%e7%bd%91%e7%ab%99%e6%89%98%e7%ae%a1%e5%8f%af%e4%bb%a5%e5%88%86%e5%bc%80" class="header-anchor"&gt;&lt;/a&gt;1. 买域名：注册商与网站托管可以分开&#10;&lt;/h2&gt;&lt;p&gt;我先比较了包含 &lt;code&gt;zouyiyi&lt;/code&gt; 等名称的域名，也考虑过 &lt;code&gt;.top&lt;/code&gt;、&lt;code&gt;.xyz&lt;/code&gt; 这样的后缀。过程中尝试了 Porkbun，但遇到身份验证没有通过的问题，最终在 NameSilo 注册了 &lt;code&gt;zouyiyi.top&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;这只是本次注册的经历。我没有拿到身份验证失败的明确原因，不能据此判断某个平台一定不支持某个国家的用户，也不建议靠随意填写身份资料来解决验证问题。价格方面，这里不记录容易过期的促销数字；购买时应分别看首年费用和后续续费费用。&lt;/p&gt;&#10;&lt;p&gt;买完域名后，我最先弄明白的是：&lt;strong&gt;域名注册商、DNS 服务商和网站托管服务商可以是不同的公司。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;在这套方案里，域名仍然在 NameSilo 管理和续费，DNS 交给 Cloudflare，博客文件也部署到 Cloudflare。把 DNS 接入 Cloudflare，并不等于把域名注册转移到了 Cloudflare Registrar。&lt;/p&gt;&#10;&lt;h2 id="2-接入-cloudflare修改的是-nameservers"&gt;&lt;a href="#2-%e6%8e%a5%e5%85%a5-cloudflare%e4%bf%ae%e6%94%b9%e7%9a%84%e6%98%af-nameservers" class="header-anchor"&gt;&lt;/a&gt;2. 接入 Cloudflare：修改的是 Nameservers&#10;&lt;/h2&gt;&lt;p&gt;我先把根域名 &lt;code&gt;zouyiyi.top&lt;/code&gt; 添加到 Cloudflare。Cloudflare 为这次接入分配了两条权威名称服务器地址：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chin.ns.cloudflare.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;denver.ns.cloudflare.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;然后在 NameSilo 的 Domain Manager 中选中域名，进入 &lt;strong&gt;Change Nameservers&lt;/strong&gt;，将原来的名称服务器替换为 Cloudflare 分配的地址，保存后等待接入状态变为 &lt;code&gt;Active&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;上面两条地址属于本次域名的分配结果。给自己的域名接入时，应复制自己 Cloudflare 页面里的地址，不要照抄。Cloudflare 的完整接入流程也要求在注册商处更新 nameservers；如果域名已有 DNS 记录或 DNSSEC，还需要按官方迁移步骤处理。&lt;a class="link" href="https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/" target="_blank" rel="noopener"&#10; &gt;Cloudflare：完整 DNS 接入流程&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;可以用下面的命令辅助检查：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig NS zouyiyi.top @1.1.1.1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dig NS zouyiyi.top @8.8.8.8&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;需要区分的是：Nameservers 决定“由谁回答这个域名的 DNS 查询”；A、AAAA、CNAME 等记录决定具体名称指向什么。接入 Cloudflare 时，不能把它给出的 nameserver 地址当作博客服务器的 IPv4 地址填写。&lt;/p&gt;&#10;&lt;h2 id="3-有了域名为什么不需要自己的公网-ip"&gt;&lt;a href="#3-%e6%9c%89%e4%ba%86%e5%9f%9f%e5%90%8d%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e9%9c%80%e8%a6%81%e8%87%aa%e5%b7%b1%e7%9a%84%e5%85%ac%e7%bd%91-ip" class="header-anchor"&gt;&lt;/a&gt;3. 有了域名，为什么不需要自己的公网 IP&#10;&lt;/h2&gt;&lt;p&gt;我最后把博客放在 &lt;code&gt;blog.zouyiyi.top&lt;/code&gt;，给登录回调使用 &lt;code&gt;blog-auth.zouyiyi.top&lt;/code&gt;。它们都是 &lt;code&gt;zouyiyi.top&lt;/code&gt; 下面的子域名，不需要再购买一个独立域名，但仍然需要配置相应的解析或服务绑定。&lt;/p&gt;&#10;&lt;p&gt;这次博客使用 Cloudflare 的托管基础设施。Hugo 生成的文件上传到 Workers Static Assets，读者访问时由 Cloudflare 提供这些资源，因此我不需要准备一台有固定公网 IP 的个人服务器。&lt;a class="link" href="https://developers.cloudflare.com/workers/static-assets/" target="_blank" rel="noopener"&#10; &gt;Cloudflare Workers Static Assets&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;具体做法是在博客 Worker 上绑定自定义域名 &lt;code&gt;blog.zouyiyi.top&lt;/code&gt;，随后检查 DNS、HTTPS 和实际页面访问，而不是只看到控制台出现一条配置就认为完成。&lt;/p&gt;&#10;&lt;p&gt;这也没有把整个域名锁定在一种托管方式里。例如，以后可以让博客继续使用 Cloudflare 托管，同时为 &lt;code&gt;api.zouyiyi.top&lt;/code&gt; 配置指向自己服务器的记录。不同子域名可以服务于不同用途。给某个子域名添加 A 记录，并不意味着其他子域名必须迁移到那台服务器。&lt;/p&gt;&#10;&lt;h2 id="4-选择-hugo-stack文章仍然是普通文件"&gt;&lt;a href="#4-%e9%80%89%e6%8b%a9-hugo-stack%e6%96%87%e7%ab%a0%e4%bb%8d%e7%84%b6%e6%98%af%e6%99%ae%e9%80%9a%e6%96%87%e4%bb%b6" class="header-anchor"&gt;&lt;/a&gt;4. 选择 Hugo Stack：文章仍然是普通文件&#10;&lt;/h2&gt;&lt;p&gt;最初上线的主题是 PaperMod，后来为了让首页更有视觉层次，换成了 &lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener"&#10; &gt;Hugo Stack&lt;/a&gt;。我希望它主要是一个学习博客，而不是按章节组织的产品文档站：以时间线展示文章，配合分类、标签、搜索、目录和代码高亮。&lt;/p&gt;&#10;&lt;p&gt;本次固定使用 Hugo Extended &lt;code&gt;0.169.0&lt;/code&gt; 和 Stack &lt;code&gt;4.0.3&lt;/code&gt;。固定版本是为了让本机和自动构建使用一致的工具；以后升级应单独验证，不把这些版本号当作永远不变的最新版本。&lt;/p&gt;&#10;&lt;p&gt;仓库里的文章统一使用 Hugo 的页面包结构：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;content/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; post/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; domain-to-cloudflare-blog/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; index.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cover.svg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; architecture.svg&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; page/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; about/index.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; archives/index.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; search/index.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;一篇文章就是一个目录。&lt;code&gt;index.md&lt;/code&gt; 放正文和文章信息，图片可以放在旁边。首页的封面、文章摘要和分类来自 Markdown 开头的 YAML 信息。&lt;/p&gt;&#10;&lt;p&gt;主题只负责展示。文章没有被锁进某个编辑器的私有格式，以后可以直接用文本编辑器、Git 工具或 agent 修改。&lt;/p&gt;&#10;&lt;h2 id="5-decap-是网页编辑器登录权限是另一回事"&gt;&lt;a href="#5-decap-%e6%98%af%e7%bd%91%e9%a1%b5%e7%bc%96%e8%be%91%e5%99%a8%e7%99%bb%e5%bd%95%e6%9d%83%e9%99%90%e6%98%af%e5%8f%a6%e4%b8%80%e5%9b%9e%e4%ba%8b" class="header-anchor"&gt;&lt;/a&gt;5. Decap 是网页编辑器，登录权限是另一回事&#10;&lt;/h2&gt;&lt;p&gt;我希望有一个能直接写文章、上传图片的后台，但又担心：放在公网，别人是不是也能编辑？&lt;/p&gt;&#10;&lt;p&gt;本次的后台位于 &lt;code&gt;/admin/&lt;/code&gt;。Decap 的前端文件和博客一起部署到 Cloudflare，在浏览器里运行；它不是一台必须在我电脑上保持运行的后台服务器。它通过 GitHub 后端读写仓库，保存文章时实际是在修改文件。&lt;/p&gt;&#10;&lt;p&gt;我为它单独配置了 GitHub OAuth 登录应用，并用另一个 Worker 处理授权回调。应用里的两个地址分别是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Homepage URL:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://blog.zouyiyi.top&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Authorization callback URL:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://blog-auth.zouyiyi.top/callback&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;登录 Worker 不只检查“是否登录了 GitHub”，还核对预先允许的 GitHub 数字账号 ID，并检查该账号是否具有博客仓库的写权限。仓库本身是私有的，没有把其他用户加入写作协作。&lt;/p&gt;&#10;&lt;p&gt;因此，访客能打开后台登录页，并不代表能读取仓库或修改文章。这里保护的是&lt;strong&gt;对内容的读写权限&lt;/strong&gt;，不是靠隐藏 &lt;code&gt;/admin/&lt;/code&gt; 地址来保护网站。&lt;/p&gt;&#10;&lt;p&gt;配置时还遇到一个细节：我一开始把 &lt;code&gt;GITHUB_CLIENT_SECRET&lt;/code&gt; 添加成了普通 Variable，后来改成了 Secret。登录服务使用的密钥只保存在 Cloudflare 的服务端绑定中，不应写进前端 JavaScript、仓库或文章示例。OAuth 需要的服务端流程可以参考 &lt;a class="link" href="https://decapcms.org/docs/github-backend/" target="_blank" rel="noopener"&#10; &gt;Decap 的 GitHub 后端说明&lt;/a&gt;。&lt;/p&gt;&#10;&lt;h2 id="6-点发布后代码怎样到达-cloudflare"&gt;&lt;a href="#6-%e7%82%b9%e5%8f%91%e5%b8%83%e5%90%8e%e4%bb%a3%e7%a0%81%e6%80%8e%e6%a0%b7%e5%88%b0%e8%be%be-cloudflare" class="header-anchor"&gt;&lt;/a&gt;6. 点“发布”后，代码怎样到达 Cloudflare&#10;&lt;/h2&gt;&lt;p&gt;为了区分草稿和正式文章，我启用了 Decap 的编辑工作流：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;github&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;YOUR_ACCOUNT/YOUR_PRIVATE_REPOSITORY&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;squash_merges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;publish_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;editorial_workflow&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;保存草稿时，Decap 会创建草稿分支和拉取请求；后续保存继续更新草稿，正式发布则合并到生产分支。这是编辑按钮与 Git 操作之间的对应关系。&lt;a class="link" href="https://decapcms.org/docs/editorial-workflows/" target="_blank" rel="noopener"&#10; &gt;Decap：Editorial Workflows&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;接着，在现有博客 Worker 的 &lt;strong&gt;Settings → Builds → Connect&lt;/strong&gt; 中连接 GitHub，授权访问博客私有仓库。本次配置为：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;设置&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;值&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生产分支&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;main&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;根目录&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;构建命令&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;python3 scripts/build.py&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;部署命令&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;python3 scripts/deploy.py&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;监听路径&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;**&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;非生产分支和预览部署&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;关闭&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这里的两个 Python 文件是本项目自己的脚本，&lt;strong&gt;不是 Cloudflare 内置命令&lt;/strong&gt;。&lt;code&gt;build.py&lt;/code&gt; 下载并校验固定版本的 Hugo Extended，再生成 &lt;code&gt;dist/&lt;/code&gt;；&lt;code&gt;deploy.py&lt;/code&gt; 收集静态资源，通过 Cloudflare API 上传并部署。构建凭证由 Cloudflare 的构建环境提供，不写进 Git。&lt;/p&gt;&#10;&lt;p&gt;Cloudflare 支持配置构建命令、部署命令、生产分支和构建凭证。复用这套思路时，需要让命令与自己的项目工具匹配，不能只复制两行命令却没有相应脚本。&lt;a class="link" href="https://developers.cloudflare.com/workers/ci-cd/builds/configuration/" target="_blank" rel="noopener"&#10; &gt;Workers Builds 配置&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;这次选择了 Cloudflare 自带的 Workers Builds，没有再配置一套 GitHub Actions。两者都是可行的自动化入口，没必要为了“自动发布”同时维护两套。&lt;/p&gt;&#10;&lt;p&gt;实际链路是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;span class="lnt"&gt;8&#10;&lt;/span&gt;&lt;span class="lnt"&gt;9&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Decap 点击发布，或者本地 git push&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; GitHub main 出现新提交&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Cloudflare 拉取仓库并运行 Hugo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 上传 dist 中的静态资源&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; blog.zouyiyi.top 展示新内容&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;关闭非生产分支部署，是为了让草稿继续留在私有仓库里，不因为一个预览网址而公开。&lt;/p&gt;&#10;&lt;h2 id="7-踩坑发布成功不等于网站已经更新"&gt;&lt;a href="#7-%e8%b8%a9%e5%9d%91%e5%8f%91%e5%b8%83%e6%88%90%e5%8a%9f%e4%b8%8d%e7%ad%89%e4%ba%8e%e7%bd%91%e7%ab%99%e5%b7%b2%e7%bb%8f%e6%9b%b4%e6%96%b0" class="header-anchor"&gt;&lt;/a&gt;7. 踩坑：发布成功不等于网站已经更新&#10;&lt;/h2&gt;&lt;p&gt;后台登录成功、能看到文章之后，我创建了一篇测试文章。随后发现两个问题：新文章没出现在首页，后台点“查看文章”也会遇到 404。&lt;/p&gt;&#10;&lt;h3 id="文章已经进了-github但没有新的构建"&gt;&lt;a href="#%e6%96%87%e7%ab%a0%e5%b7%b2%e7%bb%8f%e8%bf%9b%e4%ba%86-github%e4%bd%86%e6%b2%a1%e6%9c%89%e6%96%b0%e7%9a%84%e6%9e%84%e5%bb%ba" class="header-anchor"&gt;&lt;/a&gt;文章已经进了 GitHub，但没有新的构建&#10;&lt;/h3&gt;&lt;p&gt;排查发现，测试文章对应的拉取请求已经合并到 &lt;code&gt;main&lt;/code&gt;，Markdown 和图片也都在仓库里。但 Cloudflare 的最新成功构建仍对应更早的一次提交。&lt;/p&gt;&#10;&lt;p&gt;这就把问题缩小到了自动构建触发这一段，而不是“Decap 没保存文章”或者“Hugo 一定无法识别 Markdown”。&lt;/p&gt;&#10;&lt;p&gt;当时的监听规则是 &lt;code&gt;*&lt;/code&gt;。调整为 &lt;code&gt;**&lt;/code&gt; 后，我又做了一次&lt;strong&gt;只修改文章子目录文件&lt;/strong&gt;的合并测试，确认 Cloudflare 自动启动构建，并在公网看到了修改。&lt;/p&gt;&#10;&lt;p&gt;这里需要保留一个边界：我没有完整的 webhook 投递记录，不能仅凭这一组现象证明 &lt;code&gt;*&lt;/code&gt; 是唯一根因，更不能把“单个星号只匹配根目录”当作 Cloudflare 的通用规则。官方文档对通配符有自己的定义。此次能确认的是漏构建的现象，以及调整后的文章目录合并测试已经通过。&lt;a class="link" href="https://developers.cloudflare.com/workers/ci-cd/builds/build-watch-paths/" target="_blank" rel="noopener"&#10; &gt;Cloudflare：Build watch paths&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;真正应该留下来的检查习惯是：&lt;strong&gt;自动发布要用文章文件验证，不能只改根目录 README，看到构建成功就结束。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;h3 id="后台预览地址把-index-拼进了网址"&gt;&lt;a href="#%e5%90%8e%e5%8f%b0%e9%a2%84%e8%a7%88%e5%9c%b0%e5%9d%80%e6%8a%8a-index-%e6%8b%bc%e8%bf%9b%e4%ba%86%e7%bd%91%e5%9d%80" class="header-anchor"&gt;&lt;/a&gt;后台预览地址把 &lt;code&gt;index&lt;/code&gt; 拼进了网址&#10;&lt;/h3&gt;&lt;p&gt;另一个问题来自两套网址生成规则没有统一。&lt;/p&gt;&#10;&lt;p&gt;文章文件放在 &lt;code&gt;content/post/&amp;lt;文章目录&amp;gt;/index.md&lt;/code&gt; 中。最初 Decap 配置使用：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;preview_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;posts/{{slug}}/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;但在这个位置，Decap 的 &lt;code&gt;{{slug}}&lt;/code&gt; 表示整条条目标识，并不总是想象中的短文章名。它包含的 &lt;code&gt;index&lt;/code&gt; 部分可能生成类似 &lt;code&gt;/posts/hello-world-index/&lt;/code&gt; 的地址，而 Hugo 的实际页面地址没有这个后缀。两者不一致，自然就是 404。&lt;a class="link" href="https://decapcms.org/docs/configuration-options/#preview_path" target="_blank" rel="noopener"&#10; &gt;Decap：preview_path 的变量含义&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;最后统一采用&lt;strong&gt;文章目录名决定网址&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;span class="lnt"&gt;7&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# hugo.yaml&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;permalinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/posts/:contentbasename/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/:slug/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/posts/&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# static/admin/config.yml 中的文章集合&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;content/post&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{{slug}}/index&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;preview_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;posts/{{dirname}}/&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这样，&lt;code&gt;content/post/domain-to-cloudflare-blog/index.md&lt;/code&gt; 对应的就是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://blog.zouyiyi.top/posts/domain-to-cloudflare-blog/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这里也补上了 &lt;code&gt;section.post&lt;/code&gt; 的配置。只配置单篇文章的路径，并不代表 &lt;code&gt;/posts/&lt;/code&gt; 这个列表页会自动使用同样的地址。Hugo 可以分别设置单页和栏目页的链接规则。&lt;a class="link" href="https://gohugo.io/configuration/permalinks/" target="_blank" rel="noopener"&#10; &gt;Hugo：Permalinks&lt;/a&gt;&lt;/p&gt;&#10;&lt;p&gt;修复后实际检查了首页、文章列表、每篇文章、图片，以及后台加载到的新配置。曾经生成的错误地址也做过兼容跳转；后来清理测试文章时，对应的临时跳转一并移除了。&lt;/p&gt;&#10;&lt;h2 id="8-不用网页后台直接添加-markdown-也能发布"&gt;&lt;a href="#8-%e4%b8%8d%e7%94%a8%e7%bd%91%e9%a1%b5%e5%90%8e%e5%8f%b0%e7%9b%b4%e6%8e%a5%e6%b7%bb%e5%8a%a0-markdown-%e4%b9%9f%e8%83%bd%e5%8f%91%e5%b8%83" class="header-anchor"&gt;&lt;/a&gt;8. 不用网页后台，直接添加 Markdown 也能发布&#10;&lt;/h2&gt;&lt;p&gt;配置完成后，我意识到 Decap 只是其中一种编辑入口。既然它最后写入的也是 Git 仓库，那直接拉取代码、添加文章，再推送到 &lt;code&gt;main&lt;/code&gt;，就可以走同一条自动发布链路。&lt;/p&gt;&#10;&lt;p&gt;新文章可以这样组织：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;content/post/my-learning-note/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── index.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── cover.webp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── diagram.png&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;code&gt;index.md&lt;/code&gt; 的开头写文章信息，后面就是普通 Markdown：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;我的一次学习记录&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ld"&gt;2026-11-13T01:00:00&lt;/span&gt;&lt;span class="m"&gt;+08&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;这次遇到的问题、尝试过程和得到的结论。&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;cover.webp&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;学习笔记&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;实践&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## 遇到了什么问题&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;先描述背景，再记录尝试和验证。&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;![&lt;span class="nt"&gt;过程示意图&lt;/span&gt;](&lt;span class="na"&gt;diagram.png&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;实际写作时要替换为自己的时间、正文和图片；没有图片就省略相关字段，不能留下不存在的文件路径。&lt;code&gt;draft: true&lt;/code&gt; 会让 Hugo 跳过文章；未来时间的文章同样不会在当前构建里出现。把时间设到未来也不等于已经安排好了定时发布，时间到了仍需要一次新的构建。&lt;/p&gt;&#10;&lt;p&gt;我现在的发布操作是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 在仓库根目录，先确认没有需要保护的未提交修改&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git status --short&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git pull --ff-only&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 写好文章后，构建并检查公开文件&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 scripts/build.py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 scripts/deploy.py --check&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 只暂存本次文章与图片&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git add content/post/my-learning-note/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff --cached&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git commit -m &lt;span class="s2"&gt;&amp;#34;docs: 发布学习笔记&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git push origin main&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;上述推送命令适用于当前就在 &lt;code&gt;main&lt;/code&gt; 的情况。如果在其他分支写作，需要检查后合并到 &lt;code&gt;main&lt;/code&gt; 才会发布。&lt;code&gt;deploy.py --check&lt;/code&gt; 只检查资源，并不会直接上线；真正的部署仍由 Cloudflare 执行。&lt;/p&gt;&#10;&lt;h2 id="9-把写作规则交给-agent仓库里的-agentsmd"&gt;&lt;a href="#9-%e6%8a%8a%e5%86%99%e4%bd%9c%e8%a7%84%e5%88%99%e4%ba%a4%e7%bb%99-agent%e4%bb%93%e5%ba%93%e9%87%8c%e7%9a%84-agentsmd" class="header-anchor"&gt;&lt;/a&gt;9. 把写作规则交给 agent：仓库里的 AGENTS.md&#10;&lt;/h2&gt;&lt;p&gt;为了让后续 agent 不必重新摸索项目，我在仓库根目录增加了 &lt;code&gt;AGENTS.md&lt;/code&gt;，把这些约定写成可以执行的步骤：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;新文章放进 &lt;code&gt;content/post/&amp;lt;目录名&amp;gt;/index.md&lt;/code&gt;，配图放在同一目录。&lt;/li&gt;&#10;&lt;li&gt;按用户提供的想法写作，不虚构经历、实验结果或已经验证的结论。&lt;/li&gt;&#10;&lt;li&gt;区分“整理草稿”和“发布上线”；只有明确授权发布时才推送生产分支。&lt;/li&gt;&#10;&lt;li&gt;使用当前日期和正确时区，检查草稿状态、封面和文章链接。&lt;/li&gt;&#10;&lt;li&gt;提交前同步仓库、检查差异，不覆盖网页后台写入的新内容。&lt;/li&gt;&#10;&lt;li&gt;推送之后继续检查构建和真实网页，不能停在“Git 提交成功”。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;以后可以直接给 agent 这样的任务：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;先阅读仓库根目录的 AGENTS.md，把下面的想法整理成一篇学习笔记，检查后提交并推送到 main，确认上线后把文章链接发给我。&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;agent 需要的是博客仓库的正常 GitHub 写权限。日常写文章不需要拿到 Cloudflare 密钥，也不需要接管浏览器里的登录会话。至于具体工具是否自动读取这个文件，应以工具行为为准；在任务里明确要求“先读 AGENTS.md”最直观。&lt;/p&gt;&#10;&lt;h2 id="10-我现在怎样判断发布完成"&gt;&lt;a href="#10-%e6%88%91%e7%8e%b0%e5%9c%a8%e6%80%8e%e6%a0%b7%e5%88%a4%e6%96%ad%e5%8f%91%e5%b8%83%e5%ae%8c%e6%88%90" class="header-anchor"&gt;&lt;/a&gt;10. 我现在怎样判断“发布完成”&#10;&lt;/h2&gt;&lt;p&gt;这次搭建让我不再只看某个按钮是否显示成功，而是把结果拆开检查：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;检查位置&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;要看到的结果&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;域名接入&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloudflare 状态为 Active，权威 NS 与分配结果一致&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;GitHub&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;正文和图片已经进入 &lt;code&gt;main&lt;/code&gt;，提交内容符合预期&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloudflare Builds&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;能找到对应提交的构建，结果为成功&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;公开博客&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;文章网址正常打开，显示本次正文，图片可加载&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;首页与列表&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;新文章能被找到，链接没有多余的 &lt;code&gt;index&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;草稿与权限&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;普通访客没有写入权限，草稿分支没有公开部署&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;目前，博客的日常维护已经收敛为一件很具体的事：&lt;strong&gt;把值得留下的学习过程写成文件，并验证这些文件确实变成了可访问的文章。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;域名、DNS、登录和部署解决的是基础设施问题。接下来更重要的，是持续记录真实遇到的问题、尝试过的办法，以及最后弄明白了什么。&lt;/p&gt;&#10;</description></item></channel></rss>