视频加载失败

把 Astro 静态博客部署到 Nginx:一次可回滚的上线记录

1246 字
6 分钟
把 Astro 静态博客部署到 Nginx:一次可回滚的上线记录

Astro 静态博客的部署看起来很简单:构建,然后把 dist 上传到服务器。但真正影响上线质量的,往往是这两个动作之间被省略的部分——搜索索引是否生成、路由是否正确、证书能否续期,以及出现问题时能不能迅速回到上一版。

这篇文章记录我为本站采用的发布思路。示例中的域名和目录均为通用占位值,不对应真实服务器信息。

先确认拿到的是完整产物#

本地环境固定使用项目声明的 Node.js 与 pnpm 版本,安装依赖时遵循锁文件:

Terminal window
pnpm install --frozen-lockfile
pnpm check
pnpm type-check
pnpm build

构建结束后,我不会只看退出码,还会检查几个关键文件:

dist/index.html
dist/404.html
dist/pagefind/pagefind.js
dist/rss.xml
dist/sitemap-index.xml

其中 Pagefind 最容易被忽略。Astro 页面构建完成不代表搜索索引已经生成,正式上线必须使用项目完整的 pnpm build

Warning

如果刚删除过文章,旧的 Astro 数据缓存仍可能引用已不存在的内容。此时应清理项目构建缓存和 dist 后重新构建,而不是把不完整产物带到服务器。

服务器只接收静态文件#

站点采用本地构建、服务器托管的方式。服务器不需要安装 Node.js,也不上传源码、依赖目录或本地配置,只接收验证过的 dist 内容。

为了避免直接覆盖正在服务的目录,我把每次产物放进独立版本目录:

/var/www/example.com/
├── current -> releases/20260826-100000
└── releases/
├── 20260825-230000/
└── 20260826-100000/

上传和解压都发生在新目录。确认首页、404、搜索、RSS 与站点地图齐全后,再原子切换 current

Terminal window
ln -s releases/20260826-100000 /var/www/example.com/current.next
mv -T /var/www/example.com/current.next /var/www/example.com/current

这种结构有两个好处:切换瞬间不会出现“上传到一半”的页面,而且上一版仍然存在,回滚只需把软链接重新指回旧目录。

Nginx 要理解静态站点路由#

Astro 会为文章生成目录形式的页面,因此 Nginx 的站点根目录指向 current,并让路径依次匹配文件和目录:

server {
listen 443 ssl http2;
server_name example.com;
root /var/www/example.com/current;
index index.html;
location / {
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}

这里的 =404 很重要。若把所有未知路径都回退到首页,用户看似没有遇到错误,但搜索引擎和监控得到的状态码也是 200,真正的坏链接会被掩盖。

带哈希的 Astro 资源可以长期缓存,Pagefind 索引则保留较短缓存,方便文章更新后及时生效:

location ^~ /_astro/ {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
}
location ^~ /pagefind/ {
try_files $uri =404;
expires 1h;
add_header Cache-Control "public, max-age=3600";
}

^~ 可以防止通用图片正则覆盖 _astro 的一年缓存规则。这是一个很小的配置细节,却会直接改变封面等哈希资源的缓存时间。

DNS 与 HTTPS 必须按顺序进行#

Let’s Encrypt 的 HTTP 验证要求域名已经指向目标服务器。因此顺序应该是:

  1. 先用 HTTP 配置验证新站点;
  2. 修改根域名与 www 的 DNS 记录;
  3. 从权威 DNS 和公共解析器确认记录生效;
  4. 申请同时覆盖两个域名的证书;
  5. 启用 HTTPS,并将 HTTP 与 www 跳转到正式根域名。

证书签发成功并不等于结束。Nginx 中的 ACME 验证目录必须与 Certbot 续期配置一致,最后还要执行一次续期演练:

Terminal window
certbot renew --dry-run

如果演练失败,就应该在上线阶段修复,而不是等证书临近过期时才发现问题。

验收不止是“首页能打开”#

我的上线检查分成四层:

  • 内容:主页、文章、分类、标签、归档、搜索和关于页;
  • 协议:HTTP 跳转、www 跳转、证书域名与有效期;
  • 静态资源:Pagefind、RSS、站点地图、封面和长期缓存;
  • 错误路径:不存在页面返回定制内容,同时保持真实 404 状态码。

另外还要检查 canonical 与站点地图中的域名,避免页面已经上线,SEO 地址却仍指向开发环境或旧域名。

回滚方案要在发布前存在#

发布完成后不要马上删除旧版本。若新版本出现阻塞问题,可以把 current 指回上一版并重新加载 Nginx;静态站点不涉及数据库迁移时,这种回滚通常很快。

只有在新版本稳定运行一段时间后,才清理更早的产物,并始终保留至少一个已经验证的旧版本。

这次上线让我更确定:静态站点降低了运行时复杂度,但没有消除发布工程。完整构建、独立版本、原子切换、真实 404、证书续期和可验证回滚,才共同组成一次真正完成的部署。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

把 Astro 静态博客部署到 Nginx:一次可回滚的上线记录
https://susuji.top/posts/deploying-astro-blog-with-nginx/
作者
酥酥鸡
发布于
2026-08-26
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
酥酥鸡
前端工程师,白天写代码,晚上写生活。
公告
欢迎来到酥酥鸡的博客,这里记录前端开发、建站实践与生活片段。
分类
标签
最新动态
站点统计
文章
3
分类
3
标签
8
总字数
3,102
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.16.4
文章许可
CC BY-NC-SA 4.0