← 文章 / Writing

Engineering7 min编者 nabunana ↗

更新静态博客时,我不直接覆盖 /var/www/blog

这个 Astro 博客的发布过程:先在旁边准备好完整站点,核对资源,再一次替换并保留回滚。
#Astro#Nginx#SFTP#部署#静态网站

这个博客是 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。服务器上的临时上传包会删除,本地暂存包先留着,等这次发布确认稳定后再处理。

这套流程没有上容器、对象存储或发布平台。一个静态个人站,用暂存目录、校验和、原子替换和一份回滚备份已经够用。

今聴いている / NOW LISTENINGYorushika

读完之后,留一点安静给音乐。这是一则状态记录,不是播放器。

站内搜索

AgentVibe的东西 真的看懂了吗Notes · 工程 反思 AI 能力 · 攒了一堆能跑的项目,能力却没长进。问题不在代码谁写的,在于我有没有真正想明白。谈谈多Agent并发与OpenclawNotes · AI 工作流 OpenClaw 工程取舍 · 把一个写文案的活拆成五六个 Agent 开会,听着爽,实际是 Token 火葬场。真正把事做完的,是单 Agent 加工具,加上几个克制的角色。一次 GitHub Actions 自动发布复盘Engineering · Astro GitHub Actions Nginx SSH CI/CD 部署 · 从旧 Hexo GitHub Pages、Astro 新站到服务器:怎样处理分支切换、SSH 信任、未入库的 94 首音乐,以及可回滚的原子发布.更新静态博客时,我不直接覆盖 /var/www/blogEngineering · Astro Nginx SFTP 部署 静态网站 · 这个 Astro 博客的发布过程:先在旁边准备好完整站点,核对资源,再一次替换并保留回滚。Java 没有断,WebSocket 为什么一直重连Engineering · Java WebSocket Nginx Vue 部署 · 一次公网部署故障复盘:REST 正常、进程没重启,WebSocket 却持续 403,子路由刷新也跟着 404。做“今天吃什么”,我只想让页面给一家店Engineering · Java Vue uni-app 推荐系统 产品设计 · ELMA 目前的项目思路:少问几个问题,一次给一家店,再从反馈和行为里慢慢学。做一个能按真实尺寸打印的卡牌 PDF 工具Projects · Python Pillow PDF Tkinter Desktop · 卡牌图片放进 A4 不难,麻烦的是毫米、DPI、图片比例和桌面程序里的几个小坑。三体模拟器跑起来以后,四条链路开始互相拖后腿Engineering · Java Vue WebSocket Canvas 性能优化 · 一次实时模拟项目里的拆分:积分照常跑,网络只发该发的,画布和归档各自守住上限。聊天摘要 Agent:消息拉全以后,才轮得到模型Agent · Python Agent SQLite Privacy 容错设计 · 记录聊天摘要从能运行到可以放心使用,中间补过的分页、游标、证据和隐私边界。拿一个 8KB 数组写个 mallocSystems · C Memory Data Structure 嵌入式 · MiniMalloc 里真正需要想明白的几件事:块头放哪、空闲块怎么找,以及 free 后怎样把内存拼回去。我为什么还在用 RSSNotes · RSS Reading Web · 不猜兴趣,也不替我调整顺序。想看的来源,自己订阅就够了。这个夏天看过的动画ACG · Anime ACG Life · 没做排名,只记下几段过了一阵子还会想起来的内容。ProjectsPage · 正在构建的项目与实验MusicPage · Yorushika、n-buna、Vocaloid 与听歌记录AboutPage · 关于这个数字空间和它的主人