<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Release · XB 现场笔记</title><link>https://www.xbcatm.com/zh/tags/release/</link><description>基于 HTTP、DNS、TLS、Caddy、SSH、发布与恢复的可复现运维现场笔记。</description><generator>Hugo</generator><language>zh-CN</language><atom:link href="https://www.xbcatm.com/zh/tags/release/index.xml" rel="self" type="application/rss+xml"/><item><title>发布清单应点名每一个已发布的字节</title><link>https://www.xbcatm.com/zh/notes/a-release-manifest-should-name-every-published-byte/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/notes/a-release-manifest-should-name-every-published-byte/</guid><description>生成确定性的文件清单，并在传输前后比较。</description><content:encoded>&lt;p&gt;静态制品是一个目录，而不是一个可执行文件。只记录源码提交或只记录首页校验和会留下缺口：缺失的图片、陈旧的别名或变化的下载可能悄悄存活下来。一份发布清单应枚举每个常规文件。&lt;/p&gt;
&lt;h2 id="生成稳定的列表"&gt;生成稳定的列表&lt;/h2&gt;
&lt;p&gt;从制品根目录运行命令，使路径保持相对。在固定区域设置下按路径排序：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; public
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -type f -exec sha256sum &lt;span class="o"&gt;{}&lt;/span&gt; + &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C sort -k2 &amp;gt; ../release.sha256
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;清单是关于制品的证据，因此把它放在被测量目录之外，除非清单本身有意作为发布的一部分。&lt;/p&gt;
&lt;h2 id="传输后验证"&gt;传输后验证&lt;/h2&gt;
&lt;p&gt;在目标端，逐个文件验证：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /srv/www/site.new
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sha256sum -c /path/to/release.sha256
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这能捕获变化的字节与缺失的路径。它不会报告意外的多余文件，因此也要比较目标端的文件列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . -type f &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C sort &amp;gt; destination.files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;awk &lt;span class="s1"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt; /path/to/release.sha256 &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C sort &amp;gt; expected.files
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff -u expected.files destination.files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="为发布记录增加聚合摘要"&gt;为发布记录增加聚合摘要&lt;/h2&gt;
&lt;p&gt;对清单自身做哈希，为日志与部署记录生成一个短标识：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sha256sum release.sha256
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;聚合摘要只有在清单生成规则固定时才有意义：相对路径形式、排序区域、哈希算法，以及是否包含生成的元数据，都属于流程的一部分。&lt;/p&gt;
&lt;h2 id="不要把完整性等同于真实性"&gt;不要把完整性等同于真实性&lt;/h2&gt;
&lt;p&gt;SHA-256 证明两个字节序列一致。如果攻击者既能替换制品也能替换清单，那么这种检查不能确立是谁产生的它们。制品签名与可信分发是独立的控制手段。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/coreutils/manual/html_node/sha2-utilities.html"&gt;GNU Coreutils: sha2 utilities&lt;/a&gt;，校验和生成与检查，已核验 2026-08-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man1/sha256sum.1.html"&gt;sha256sum(1)&lt;/a&gt;，命令行为与输出格式，已核验 2026-08-23。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>通过切换完整目录发布静态网站</title><link>https://www.xbcatm.com/zh/notes/publish-a-static-site-by-switching-complete-directories/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/notes/publish-a-static-site-by-switching-complete-directories/</guid><description>在活动树旁边预置一份完整制品，并只在验证后替换目录名。</description><content:encoded>&lt;p&gt;直接把新文件复制到活动的静态目录上，会造成一段访问者可能从一个版本拿到 HTML、从另一个版本拿到资源的时期。更安全的模式是：在活动树旁预置一棵完整的树，验证它，再改变目录名。&lt;/p&gt;
&lt;h2 id="把所有发布目录放在同一文件系统上"&gt;把所有发布目录放在同一文件系统上&lt;/h2&gt;
&lt;p&gt;当活动树、预置树与回滚树共享同一文件系统与父目录时，名字替换最强。先检查：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;df -P /srv/www
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在该父目录下创建唯一命名的中转目录。不要把未解析的变量或宽泛通配符当成删除目标来复用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp -d /srv/www/site.new.XXXXXX&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="填充并验证预置目录"&gt;填充并验证预置目录&lt;/h2&gt;
&lt;p&gt;把生成制品复制进空目录，然后检查代表性文件与期望的文件数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tar -C public -cf - . &lt;span class="p"&gt;|&lt;/span&gt; tar -C &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -xf -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/index.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;/404.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -type f &lt;span class="p"&gt;|&lt;/span&gt; wc -l
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当工具支持目录参数时，对预置路径运行链接与校验和检查。未通过验证的预置目录绝不能获得活动目录的名字。&lt;/p&gt;
&lt;h2 id="用显式回滚路径切换名字"&gt;用显式回滚路径切换名字&lt;/h2&gt;
&lt;p&gt;在第一次移动前解析每个路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;live&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/srv/www/site
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;stamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date -u +%Y%m%dT%H%M%SZ&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;rollback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/srv/www/site.old-&lt;span class="nv"&gt;$stamp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$live&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -d &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; ! -e &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$rollback&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$live&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$rollback&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$stage&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$live&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -s &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$live&lt;/span&gt;&lt;span class="s2"&gt;/index.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; mv &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$rollback&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$live&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段序列在两个移动之间留下一个短窗口。对每次请求都对根的单一静态服务进程来说，该窗口通常很小但仍可观察。平台特定的 rename 或符号链接模式可以收紧切换；在依赖更强断言之前，请测试确切的文件系统与服务器行为。&lt;/p&gt;
&lt;h2 id="验证公共边缘"&gt;验证公共边缘&lt;/h2&gt;
&lt;p&gt;切换之后，请求首页、一个深层路由、一个带指纹的资源与一个缺失路径。把公共字节与预置制品比较。在检查完成与观察窗口结束之前，保留回滚目录。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pubs.opengroup.org/onlinepubs/9799919799/functions/rename.html"&gt;POSIX &lt;code&gt;rename()&lt;/code&gt;&lt;/a&gt;，名字替换语义，已核验 2026-08-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/rename.2.html"&gt;Linux &lt;code&gt;rename(2)&lt;/code&gt;&lt;/a&gt;，文件系统与替换行为，已核验 2026-08-23。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/tar/manual/tar.html"&gt;GNU tar manual&lt;/a&gt;，归档创建与解包，已核验 2026-08-23。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>发布在公共边缘一致之前不算完成</title><link>https://www.xbcatm.com/zh/notes/a-release-is-not-complete-until-the-public-edge-agrees/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/notes/a-release-is-not-complete-until-the-public-edge-agrees/</guid><description>把生成制品与访问者实际能收到的响应进行比较。</description><content:encoded>&lt;p&gt;静态发布消除了应用运行时的复杂度，但不会消除生成目录与公共响应之间的边界。发布检查应同时覆盖两边。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://www.xbcatm.com/diagrams/release-path.svg" alt="一条小的静态发布路径" /&gt;
&lt;/p&gt;
&lt;h2 id="从干净的制品开始"&gt;从干净的制品开始&lt;/h2&gt;
&lt;p&gt;使用固定生成器构建到干净的目录。记录源码提交、生成器版本、输出文件列表，以及用户会下载的文件的校验和。一次干净的构建能捕获复制式部署可能会意外保留的陈旧文件。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make verify
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find public -type f -print &lt;span class="p"&gt;|&lt;/span&gt; sort
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;文件列表是证据，不是装饰。如果某条路由消失，diff 应能说明是该来源被移除，还是生成器未能产出它。&lt;/p&gt;
&lt;h2 id="演练三类响应"&gt;演练三类响应&lt;/h2&gt;
&lt;p&gt;请求一个 HTML 页面、一个静态资源与一个缺失路径。检查状态码、内容类型、缓存策略与安全头：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsS -D - -o /dev/null https://www.example.test/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsS -D - -o /dev/null https://www.example.test/downloads/check-http-headers.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -sS -D - -o /dev/null https://www.example.test/does-not-exist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第三条命令有意不用 &lt;code&gt;-f&lt;/code&gt;：404 是预期结果，仍应被捕获。把公共正文与生成的 &lt;code&gt;404.html&lt;/code&gt; 比较，并确认状态始终为 404。&lt;/p&gt;
&lt;h2 id="让回滚保持简单"&gt;让回滚保持简单&lt;/h2&gt;
&lt;p&gt;在新目录通过检查之前，不要删除上一个目录。回滚应选择一个已知良好目录，而不是在事故中凭记忆重新构造一个。&lt;a href="https://www.xbcatm.com/zh/resources/"&gt;发布检查清单&lt;/a&gt;与&lt;a href="https://www.xbcatm.com/zh/resources/"&gt;HTTP 响应头检查&lt;/a&gt;都刻意做得足够小，能在干净的 shell 里运行。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9110.html"&gt;RFC 9110 — HTTP Semantics&lt;/a&gt;，状态与表示语义，已核验 2026-08-22。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://curl.se/docs/manpage.html"&gt;curl manual&lt;/a&gt;，响应检查选项，已核验 2026-08-22。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbcatm.com/zh/resources/"&gt;静态网站发布检查清单&lt;/a&gt;，本地配套资源。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>静态网站的发布检查清单</title><link>https://www.xbcatm.com/zh/notes/a-release-checklist-for-a-static-site/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/zh/notes/a-release-checklist-for-a-static-site/</guid><description>每个发布都值得一组小、快、针对性强、且会为真实原因失败的检查。</description><content:encoded>&lt;p&gt;静态网站发布很简单，但简单并不免除发布检查的需要。有用的检查足够小，能在每次发布运行，也足够具体，能为真实的理由而失败。&lt;/p&gt;
&lt;h2 id="构建干净的制品"&gt;构建干净的制品&lt;/h2&gt;
&lt;p&gt;使用固定版本的生成器，构建到一次性的输出目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo --gc --minify --destination public
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;确切命令因项目而异，但关键属性是：输出能从受跟踪的源码复现。不要在构建之后手改生成的 HTML。&lt;/p&gt;
&lt;h2 id="检查制品而不只是源码"&gt;检查制品，而不只是源码&lt;/h2&gt;
&lt;p&gt;检视生成的树，确认期望的入口点存在：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s public/index.html
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s public/404.html
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s public/robots.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;test&lt;/span&gt; -s public/sitemap.xml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find public -type f -print &lt;span class="p"&gt;|&lt;/span&gt; sort
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后搜索意外的占位符、本地路径与仅开发用的主机：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rg -n &lt;span class="s1"&gt;&amp;#39;localhost|127\.0\.0\.1|TODO|example\.com|/Users/&amp;#39;&lt;/span&gt; public --glob &lt;span class="s1"&gt;&amp;#39;!notes/a-release-checklist-for-a-static-site/**&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;文章里有意保留的示例应用围栏明确标注为示例。链接里的主机名或私有路径通常是发布错误。&lt;/p&gt;
&lt;h2 id="验证公共路由"&gt;验证公共路由&lt;/h2&gt;
&lt;p&gt;在本地提供制品并请求访问者可达的路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hugo server --bind 127.0.0.1 --port &lt;span class="m"&gt;1313&lt;/span&gt; --disableFastRender
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I http://127.0.0.1:1313/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I http://127.0.0.1:1313/notes/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I http://127.0.0.1:1313/resources/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I http://127.0.0.1:1313/missing-page/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;确认 404 路由在生产服务器上返回 404 状态。一个外观精美但状态 200 的错误页，仍然会破坏监控与缓存。&lt;/p&gt;
&lt;h2 id="记录结果"&gt;记录结果&lt;/h2&gt;
&lt;p&gt;在发布记录中保留源码提交、生成器版本与每个可下载资源的校验和。这样无需依赖记忆，就能把线上文件与产生它的源码进行比较。&lt;/p&gt;
&lt;p&gt;这份检查清单的可下载版本在&lt;a href="https://www.xbcatm.com/zh/resources/"&gt;资源&lt;/a&gt;一节中。&lt;/p&gt;
&lt;h2 id="来源"&gt;来源&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gohugo.io/commands/hugo/"&gt;Hugo command reference&lt;/a&gt;，干净生产构建的生成器标志，已核验 2026-08-22。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://curl.se/docs/manpage.html"&gt;curl manual&lt;/a&gt;，HTTP 验证与响应头检查选项，已核验 2026-08-22。&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.xbcatm.com/zh/resources/"&gt;静态网站发布检查清单&lt;/a&gt;，可下载的配套资源。&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>