这个博客是 Astro 静态站,Nginx 直接读取 /var/www/blog。只看代码的话,发布似乎就是把 dist 传到服务器。站里放了 94 首 MP3、对应的 LRC 和 7 张专辑封面以后,构建产物已经接近 400 MB,直接覆盖线上目录不太合适。
文件传到一半断线,线上可能只剩半套资源;先删旧目录再上传,整个上传过程都会是停站状态。HTML 更新了、音频还没到时,页面能开,但播放器会随机 404。这种故障不难修,只是没必要主动制造。
构建完成后先数一遍
项目使用现有的 package-lock.json 和 npm 流程:
npm ci
npm run build
build 会先跑 astro check,再生成静态页面。那次发布前核对的是 19 个 HTML、94 个 MP3、94 个 LRC 和 7 张封面。数字本身不负责证明页面好用,但少了一项就不用继续上传。
本地还要用生产预览检查首页、音乐页和文章页。播放器的展开、固定、跨页续播,日文歌词与中文译文配对,Summer / Night 两种环境,以及手机宽度下的遮挡,构建日志都看不出来。
新站在旁边准备
发布时先把完整 dist 打包到一个新的暂存位置,不碰正在服务的目录。上传完成后比较本地和服务器文件的 SHA-256,再解压到新的站点目录,重新核对页面、音频、歌词和封面数量。
第一次用递归 SCP 传这批文件,连接中途重置。后来改成带 keepalive 的 SFTP,并从已有内容继续传。大文件多的时候,传输工具是否能恢复,比命令短不短更实际。
新目录准备好以后,再给当前 /var/www/blog 留一份带时间的完整备份,然后通过目录重命名完成切换。Nginx 看到的是一套已经齐全的文件,不会经历 HTML 和媒体资源逐个更新的中间状态。
切换后执行 nginx -t,检查服务状态,再从公网访问首页、音乐页和一篇文章。播放器还要单独发带 Range 的音频请求,确认返回 206。普通 GET 返回 200,只能说明整首文件能下载,不能证明拖动进度和断点播放可用。
目前回滚也很直接:新站有问题,就把保留的旧目录换回来,再检查 Nginx。服务器上的临时上传包会删除,本地暂存包先留着,等这次发布确认稳定后再处理。
这套流程没有上容器、对象存储或发布平台。一个静态个人站,用暂存目录、校验和、原子替换和一份回滚备份已经够用。