<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>酥酥鸡</title><description>一边写代码，一边记录生活</description><link>https://susuji.top/</link><templateTheme>Firefly</templateTheme><templateThemeVersion>6.16.4</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>2026年8月26日 01:10:07</lastBuildDate><item><title>你好，这里是酥酥鸡的博客</title><link>https://susuji.top/posts/hello-susuji/</link><guid isPermaLink="true">https://susuji.top/posts/hello-susuji/</guid><description>从今天开始，在自己的小站里认真记录前端技术、建站实践与平凡生活。</description><pubDate>Wed, 26 Aug 2026 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;你好，欢迎来到酥酥鸡的博客。&lt;/p&gt;
&lt;p&gt;这是这个小站正式发布后的第一篇文章。比起把它当成一份精心包装的个人简历，我更愿意把它看作一张长期使用的书桌：一边放正在学习的技术，一边放生活里值得记住的小事。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;为什么重新拥有一个博客&lt;a href=&quot;#为什么重新拥有一个博客&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;平时接触到的知识很零散。一个报错的解决办法、一个组件的设计取舍，或者一次部署踩过的坑，如果只停留在聊天记录和临时笔记里，很快就会失去上下文。&lt;/p&gt;&lt;p&gt;博客给了这些内容一个更稳定的位置。写作也迫使我重新检查自己的理解：哪些只是“碰巧跑通”，哪些才是真正可以复用的方法。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Note&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;这里的文章会尽量区分事实、判断和个人偏好。能够验证的内容会给出过程，仍有不确定性的地方也会明确说明。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;这里会写什么&lt;a href=&quot;#这里会写什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;目前计划记录三类内容：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;前端开发：Astro、组件设计、样式系统、性能和可访问性；&lt;/li&gt;
&lt;li&gt;建站实践：静态博客、搜索、Nginx、HTTPS、发布与回滚；&lt;/li&gt;
&lt;li&gt;生活随笔：那些不适合写成教程，却值得留下来的片段。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;技术文章不会为了显得完整而虚构环境，生活内容也不会为了更新频率而勉强拼凑。比起追求数量，我更希望每一篇内容在一段时间后仍然对自己或读者有用。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;关于这个小站&lt;a href=&quot;#关于这个小站&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本站使用 &lt;a href=&quot;https://astro.build/&quot; target=&quot;_blank&quot;&gt;Astro&lt;/a&gt; 构建，界面基于 &lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot; target=&quot;_blank&quot;&gt;Firefly&lt;/a&gt; 主题定制。它最终会生成纯静态文件，由 Nginx 提供访问；站内搜索由 Pagefind 在构建阶段生成索引。&lt;/p&gt;&lt;p&gt;我保留了 Firefly 的开源署名，同时调整了配色、布局、字体和侧边栏，让它更像属于自己的空间。关于这部分的具体过程，会在后面的文章里慢慢展开。&lt;/p&gt;&lt;p&gt;如果你愿意持续关注，可以使用本站的 &lt;a href=&quot;/rss/&quot;&gt;RSS&lt;/a&gt; 订阅。现在内容还不多，但这张书桌已经摆好了。&lt;/p&gt;&lt;p&gt;感谢来访，我们下一篇见。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>从 Firefly 到「酥酥鸡」：我的博客定制记录</title><link>https://susuji.top/posts/customizing-firefly-blog/</link><guid isPermaLink="true">https://susuji.top/posts/customizing-firefly-blog/</guid><description>记录我如何在保留 Firefly 能力的同时，清理演示内容、收敛功能并完成个人化配置。</description><pubDate>Wed, 26 Aug 2026 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;选择一个成熟主题的价值，不是省掉所有思考，而是把精力从“重复造基础设施”转移到“这个网站究竟应该是什么样”。&lt;/p&gt;
&lt;p&gt;我的博客以 &lt;a href=&quot;https://github.com/CuteLeaf/Firefly&quot; target=&quot;_blank&quot;&gt;Firefly&lt;/a&gt; 为起点。它提供了文章、归档、分类、标签、Pagefind 搜索、RSS、评论适配和多种扩展页面。真正开始定制后，我做的第一件事却不是继续加功能，而是先做减法。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先让配置与内容一致&lt;a href=&quot;#先让配置与内容一致&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Firefly 的页面开关很丰富，演示项目也准备了动态、相册、友链、留言和追番等示例。如果没有真实数据却把入口全部打开，读者看到的只会是空页面或主题作者的演示内容。&lt;/p&gt;&lt;p&gt;因此，第一版只保留这些核心入口：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;首页；&lt;/li&gt;
&lt;li&gt;文章归档、分类与标签；&lt;/li&gt;
&lt;li&gt;搜索；&lt;/li&gt;
&lt;li&gt;关于页；&lt;/li&gt;
&lt;li&gt;RSS。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;其他页面继续保留代码能力，但通过 &lt;code&gt;siteConfig.pages&lt;/code&gt; 关闭。等到有真实内容和维护意愿时，再重新启用会更稳妥。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Tip&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;页面隐藏不等于内容一定不会输出。像动态页这样的功能还可能生成 JSON 数据接口，所以演示文件也需要清理，不能只删导航链接。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;建立清晰的视觉方向&lt;a href=&quot;#建立清晰的视觉方向&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我没有完全重做主题，而是围绕统一的视觉目标调整现有系统：以蓝色为主色，扩大内容区域，使用更适合中文阅读的字体，并保留卡片边框与轻量阴影。&lt;/p&gt;&lt;p&gt;导航负责帮助读者快速抵达内容，侧边栏则承担氛围和辅助信息。时钟、每日一言、运行时间与樱花效果都可以存在，但它们不能抢过正文。动效和装饰最终都要服从同一个判断：是否会影响阅读、性能或移动端布局。&lt;/p&gt;&lt;p&gt;亮色与暗色模式也不能只检查首页。文章卡片、代码块、提示框、标签、页脚和移动端菜单都需要分别验证，否则很容易在某个局部出现对比度不足或背景突兀的问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;文章结构比页面数量更重要&lt;a href=&quot;#文章结构比页面数量更重要&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Firefly 使用 Astro Content Collections 管理文章。每篇文章可以使用 Markdown 或 MDX，Frontmatter 负责标题、发布日期、描述、封面、分类、标签、草稿和评论等元数据。&lt;/p&gt;&lt;p&gt;我选择让每篇文章拥有独立目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/content/posts/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;└── customizing-firefly-blog/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├── index.md&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── cover.png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这样文章 URL 由目录名稳定决定，封面和后续插图也能与正文放在一起。Frontmatter 中只需使用相对路径：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;./cover.png&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;本地图片会进入 Astro 的图像处理流程，再按照站点配置输出 WebP。相比随机图片 API，这种方式没有第三方可用性和防盗链风险，也更容易保持整站风格统一。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;“构建成功”要包含搜索&lt;a href=&quot;#构建成功要包含搜索&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这个项目的正式构建命令不是单独执行 Astro，而是：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;原因是完整脚本还会执行 Pagefind 等后处理。如果只运行 &lt;code&gt;pnpm exec astro build&lt;/code&gt;，页面可能看起来正常，但 &lt;code&gt;dist/pagefind/&lt;/code&gt; 不完整，部署后搜索就会失效。&lt;/p&gt;&lt;p&gt;我的本地验收至少包含以下项目：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;类型与内容 Schema 检查通过；&lt;/li&gt;
&lt;li&gt;完整生产构建零错误；&lt;/li&gt;
&lt;li&gt;首页、文章页、分类、标签和归档内容正确；&lt;/li&gt;
&lt;li&gt;中文关键词能够被 Pagefind 搜到；&lt;/li&gt;
&lt;li&gt;RSS、站点地图、404 和 canonical 地址正确；&lt;/li&gt;
&lt;li&gt;桌面与手机、亮色与暗色模式都没有布局溢出。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;保留主题能力，但不被主题牵着走&lt;a href=&quot;#保留主题能力但不被主题牵着走&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我仍然保留 Firefly 的 Logo、Favicon 和开源署名，也保留未来重新开启评论、友链或相册的可能。不过，第一版不会因为“主题支持”就默认公开所有功能。&lt;/p&gt;&lt;p&gt;这次定制最大的收获不是改了多少 CSS，而是逐渐明确了一条边界：配置应该服务真实内容，功能应该对应持续维护的承诺。先把三篇文章写好，比先摆出十个空栏目更重要。&lt;/p&gt;&lt;/section&gt;</content:encoded></item><item><title>把 Astro 静态博客部署到 Nginx：一次可回滚的上线记录</title><link>https://susuji.top/posts/deploying-astro-blog-with-nginx/</link><guid isPermaLink="true">https://susuji.top/posts/deploying-astro-blog-with-nginx/</guid><description>从完整构建、静态路由和缓存，到 DNS、HTTPS、原子切换与回滚的一次上线复盘。</description><pubDate>Wed, 26 Aug 2026 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Astro 静态博客的部署看起来很简单：构建，然后把 &lt;code&gt;dist&lt;/code&gt; 上传到服务器。但真正影响上线质量的，往往是这两个动作之间被省略的部分——搜索索引是否生成、路由是否正确、证书能否续期，以及出现问题时能不能迅速回到上一版。&lt;/p&gt;
&lt;p&gt;这篇文章记录我为本站采用的发布思路。示例中的域名和目录均为通用占位值，不对应真实服务器信息。&lt;/p&gt;
&lt;section&gt;&lt;h2&gt;先确认拿到的是完整产物&lt;a href=&quot;#先确认拿到的是完整产物&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;本地环境固定使用项目声明的 Node.js 与 pnpm 版本，安装依赖时遵循锁文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--frozen-lockfile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type-check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;构建结束后，我不会只看退出码，还会检查几个关键文件：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dist/index.html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dist/404.html&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dist/pagefind/pagefind.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dist/rss.xml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;dist/sitemap-index.xml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;其中 Pagefind 最容易被忽略。Astro 页面构建完成不代表搜索索引已经生成，正式上线必须使用项目完整的 &lt;code&gt;pnpm build&lt;/code&gt;。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Warning&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;如果刚删除过文章，旧的 Astro 数据缓存仍可能引用已不存在的内容。此时应清理项目构建缓存和 &lt;code&gt;dist&lt;/code&gt; 后重新构建，而不是把不完整产物带到服务器。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;服务器只接收静态文件&lt;a href=&quot;#服务器只接收静态文件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;站点采用本地构建、服务器托管的方式。服务器不需要安装 Node.js，也不上传源码、依赖目录或本地配置，只接收验证过的 &lt;code&gt;dist&lt;/code&gt; 内容。&lt;/p&gt;&lt;p&gt;为了避免直接覆盖正在服务的目录，我把每次产物放进独立版本目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/var/www/example.com/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── current -&amp;gt; releases/20260826-100000&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;└── releases/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;├── 20260825-230000/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── 20260826-100000/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;上传和解压都发生在新目录。确认首页、404、搜索、RSS 与站点地图齐全后，再原子切换 &lt;code&gt;current&lt;/code&gt;：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;ln&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-s&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;releases/20260826-100000&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/www/example.com/current.next&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;mv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-T&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/www/example.com/current.next&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/www/example.com/current&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;这种结构有两个好处：切换瞬间不会出现“上传到一半”的页面，而且上一版仍然存在，回滚只需把软链接重新指回旧目录。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;Nginx 要理解静态站点路由&lt;a href=&quot;#nginx-要理解静态站点路由&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Astro 会为文章生成目录形式的页面，因此 Nginx 的站点根目录指向 &lt;code&gt;current&lt;/code&gt;，并让路径依次匹配文件和目录：&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;listen &lt;/span&gt;&lt;span&gt;443&lt;/span&gt;&lt;span&gt; ssl http2;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;server_name &lt;/span&gt;&lt;span&gt;example.com;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;root &lt;/span&gt;&lt;span&gt;/var/www/example.com/current;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;index &lt;/span&gt;&lt;span&gt;index.html;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt; / {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;       &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;try_files &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt;/ &lt;/span&gt;&lt;span&gt;=404&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;error_page &lt;/span&gt;&lt;span&gt;404&lt;/span&gt;&lt;span&gt; /404.html;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt; = &lt;/span&gt;&lt;span&gt;/404.html &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;internal&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;=404&lt;/code&gt; 很重要。若把所有未知路径都回退到首页，用户看似没有遇到错误，但搜索引擎和监控得到的状态码也是 200，真正的坏链接会被掩盖。&lt;/p&gt;&lt;p&gt;带哈希的 Astro 资源可以长期缓存，Pagefind 索引则保留较短缓存，方便文章更新后及时生效：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt; ^~ &lt;/span&gt;&lt;span&gt;/_astro/ &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;try_files &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=404&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;expires &lt;/span&gt;&lt;span&gt;1y;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;add_header &lt;/span&gt;&lt;span&gt;Cache-Control &lt;/span&gt;&lt;span&gt;&quot;public, immutable&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;location&lt;/span&gt;&lt;span&gt; ^~ &lt;/span&gt;&lt;span&gt;/pagefind/ &lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;try_files &lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;uri&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=404&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;expires &lt;/span&gt;&lt;span&gt;1h&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;   &lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;add_header &lt;/span&gt;&lt;span&gt;Cache-Control &lt;/span&gt;&lt;span&gt;&quot;public, max-age=3600&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;^~&lt;/code&gt; 可以防止通用图片正则覆盖 &lt;code&gt;_astro&lt;/code&gt; 的一年缓存规则。这是一个很小的配置细节，却会直接改变封面等哈希资源的缓存时间。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;DNS 与 HTTPS 必须按顺序进行&lt;a href=&quot;#dns-与-https-必须按顺序进行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Let’s Encrypt 的 HTTP 验证要求域名已经指向目标服务器。因此顺序应该是：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;先用 HTTP 配置验证新站点；&lt;/li&gt;
&lt;li&gt;修改根域名与 &lt;code&gt;www&lt;/code&gt; 的 DNS 记录；&lt;/li&gt;
&lt;li&gt;从权威 DNS 和公共解析器确认记录生效；&lt;/li&gt;
&lt;li&gt;申请同时覆盖两个域名的证书；&lt;/li&gt;
&lt;li&gt;启用 HTTPS，并将 HTTP 与 &lt;code&gt;www&lt;/code&gt; 跳转到正式根域名。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;证书签发成功并不等于结束。Nginx 中的 ACME 验证目录必须与 Certbot 续期配置一致，最后还要执行一次续期演练：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;certbot&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;renew&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--dry-run&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果演练失败，就应该在上线阶段修复，而不是等证书临近过期时才发现问题。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;验收不止是“首页能打开”&lt;a href=&quot;#验收不止是首页能打开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;我的上线检查分成四层：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;内容：主页、文章、分类、标签、归档、搜索和关于页；&lt;/li&gt;
&lt;li&gt;协议：HTTP 跳转、&lt;code&gt;www&lt;/code&gt; 跳转、证书域名与有效期；&lt;/li&gt;
&lt;li&gt;静态资源：Pagefind、RSS、站点地图、封面和长期缓存；&lt;/li&gt;
&lt;li&gt;错误路径：不存在页面返回定制内容，同时保持真实 404 状态码。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;另外还要检查 canonical 与站点地图中的域名，避免页面已经上线，SEO 地址却仍指向开发环境或旧域名。&lt;/p&gt;&lt;/section&gt;
&lt;section&gt;&lt;h2&gt;回滚方案要在发布前存在&lt;a href=&quot;#回滚方案要在发布前存在&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;发布完成后不要马上删除旧版本。若新版本出现阻塞问题，可以把 &lt;code&gt;current&lt;/code&gt; 指回上一版并重新加载 Nginx；静态站点不涉及数据库迁移时，这种回滚通常很快。&lt;/p&gt;&lt;p&gt;只有在新版本稳定运行一段时间后，才清理更早的产物，并始终保留至少一个已经验证的旧版本。&lt;/p&gt;&lt;p&gt;这次上线让我更确定：静态站点降低了运行时复杂度，但没有消除发布工程。完整构建、独立版本、原子切换、真实 404、证书续期和可验证回滚，才共同组成一次真正完成的部署。&lt;/p&gt;&lt;/section&gt;</content:encoded></item></channel></rss>