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

Astro 静态博客的部署看起来很简单:构建,然后把 dist 上传到服务器。但真正影响上线质量的,往往是这两个动作之间被省略的部分——搜索索引是否生成、路由是否正确、证书能否续期,以及出现问题时能不能迅速回到上一版。
这篇文章记录我为本站采用的发布思路。示例中的域名和目录均为通用占位值,不对应真实服务器信息。
先确认拿到的是完整产物
本地环境固定使用项目声明的 Node.js 与 pnpm 版本,安装依赖时遵循锁文件:
pnpm install --frozen-lockfilepnpm checkpnpm type-checkpnpm build构建结束后,我不会只看退出码,还会检查几个关键文件:
dist/index.htmldist/404.htmldist/pagefind/pagefind.jsdist/rss.xmldist/sitemap-index.xml其中 Pagefind 最容易被忽略。Astro 页面构建完成不代表搜索索引已经生成,正式上线必须使用项目完整的 pnpm build。
如果刚删除过文章,旧的 Astro 数据缓存仍可能引用已不存在的内容。此时应清理项目构建缓存和 dist 后重新构建,而不是把不完整产物带到服务器。
服务器只接收静态文件
站点采用本地构建、服务器托管的方式。服务器不需要安装 Node.js,也不上传源码、依赖目录或本地配置,只接收验证过的 dist 内容。
为了避免直接覆盖正在服务的目录,我把每次产物放进独立版本目录:
/var/www/example.com/├── current -> releases/20260826-100000└── releases/ ├── 20260825-230000/ └── 20260826-100000/上传和解压都发生在新目录。确认首页、404、搜索、RSS 与站点地图齐全后,再原子切换 current:
ln -s releases/20260826-100000 /var/www/example.com/current.nextmv -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 验证要求域名已经指向目标服务器。因此顺序应该是:
- 先用 HTTP 配置验证新站点;
- 修改根域名与
www的 DNS 记录; - 从权威 DNS 和公共解析器确认记录生效;
- 申请同时覆盖两个域名的证书;
- 启用 HTTPS,并将 HTTP 与
www跳转到正式根域名。
证书签发成功并不等于结束。Nginx 中的 ACME 验证目录必须与 Certbot 续期配置一致,最后还要执行一次续期演练:
certbot renew --dry-run如果演练失败,就应该在上线阶段修复,而不是等证书临近过期时才发现问题。
验收不止是“首页能打开”
我的上线检查分成四层:
- 内容:主页、文章、分类、标签、归档、搜索和关于页;
- 协议:HTTP 跳转、
www跳转、证书域名与有效期; - 静态资源:Pagefind、RSS、站点地图、封面和长期缓存;
- 错误路径:不存在页面返回定制内容,同时保持真实 404 状态码。
另外还要检查 canonical 与站点地图中的域名,避免页面已经上线,SEO 地址却仍指向开发环境或旧域名。
回滚方案要在发布前存在
发布完成后不要马上删除旧版本。若新版本出现阻塞问题,可以把 current 指回上一版并重新加载 Nginx;静态站点不涉及数据库迁移时,这种回滚通常很快。
只有在新版本稳定运行一段时间后,才清理更早的产物,并始终保留至少一个已经验证的旧版本。
这次上线让我更确定:静态站点降低了运行时复杂度,但没有消除发布工程。完整构建、独立版本、原子切换、真实 404、证书续期和可验证回滚,才共同组成一次真正完成的部署。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














