搬一次站,比读十篇部署教程有用。
这台机器从一台空白的 Ubuntu 24.04 开始,装依赖、配 Caddy、接数据库、绑域名,中间踩了六个坑。记下来,下次换机器直接用。
真正花时间的从来不是「装什么」,而是三件事:
代码和配置都是可以重来的,数据不是。
第一次跑 sudo 得到这样一句:
sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
不是没配密码,而是内核层面禁用了 setuid 提权(NoNewPrivs=1)。这种限制一旦由父进程设下,子进程只能继承,无法撤销。检查方法很简单:
grep NoNewPrivs /proc/self/status
对运维来说这条约束的意义在于:如果一个进程本来就跑在受限上下文里,任何「脚本里 sudo 一下」的部署方案都会失败。部署脚本必须准备好「无 root 也能跑」的降级路径,否则一定会在某个环境里卡住。
Caddy 拿证书确实省心,buyao.online { ... } 写完重启,剩下的它自己办。日志里能看到完整过程:
trying to solve challenge identifier=buyao.online challenge_type=http-01
authorization finalized authz_status=valid
certificate obtained successfully
但自动化只覆盖「证书」这一段,域名解析仍然是人手动配的。这次就出一个事故:加 www 记录时,把原来的 @ 记录覆盖掉了。表现很有意思——
/api/* 走真实网络,全部失败。排查时最有用的一条证据是:看服务端日志里有没有请求进来。没有请求,问题就在 DNS 或网络,不在服务。
dig +short @amos.dnspod.net buyao.online A # 直接问权威服务器,绕开所有缓存
服务单元里加这些是好事:
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/dsh/demo/buyao-blog/server/data
但它们同时定义了「服务能看见什么」:ProtectHome=read-only 让 /home 只读,ReadWritePaths 单独放行数据目录。于是代码放哪、数据放哪,必须在部署前就想好,不能等报错了再挪。
另一个容易忽略的是 WorkingDirectory 与相对路径的关系。Node 服务里任何 ./data 都相对它解析,而不是相对仓库根。
单机小站用 SQLite 完全够用,但它的两个特性必须理解:
WAL 模式下,最近的写入可能还在 -wal 文件里。 直接 cp blog.db 会丢数据,正确做法是用 VACUUM INTO 做在线快照:
sqlite3 blog.db "VACUUM INTO '/tmp/snapshot.db'"
热恢复会把数据搞丢。 如果旧连接还持着数据库文件,它退出时的 WAL checkpoint 可能把旧的数据页写回你刚替换的新文件。表现就是:
恢复显示成功,重启之后文章变 0。
所以恢复流程必须是「停服务 → 换库 → 起服务」,没有例外。
还有个很隐蔽的坑:手工备份和定时备份落在了不同目录。定时器通过环境变量指定备份目录,手工执行时却回落到仓库内的默认路径。结果就是照着文档去 ~/backups/db 取「最新备份」,拿到的其实是当天凌晨的旧快照。这类问题不会报错,只会让你在恢复之后隐约觉得「好像少了几条评论」。
首屏最贵的一笔流量通常是头图。一张 1280×1700 的竖图原图 835KB,而首页主卡实际显示宽度不到 900px。
做法是上传时顺手生成两档派生图:
| 档位 | 尺寸 | 体积 |
|---|---|---|
| 原图 | 1280×1700 | 835 KB |
| 头图档 | 1280 宽 WebP | 97 KB |
| 卡片档 | 480 宽 WebP | 28 KB |
前端优先取派生图,缺失时 onerror 回退原图。没有 ffmpeg 也不能让上传失败——这只是优化项。
竖图还有第二个问题:object-fit: cover 只露出中间一条,主体经常被裁。这个用存一个焦点坐标解决,前端按 object-position 渲染,后台可以拖着调。
/home/dsh/backups 和数据库在同一块盘上。盘坏了、误删了、整机重装,数据和备份一起消失。
异地备份最简单的形态是本地拉取:服务器在 NAT 后面,推不出去,那就让本地电脑定时来拉。
# 本地执行
rsync -avz -e "ssh -i ~/.ssh/buyao-backup" \
buyao-backup@<host>:/srv/buyao-backup/ ~/buyao-backup/
服务器上那个账号只读、只能密钥登录、读不到其他目录。备份里含密码哈希和有效会话,等同于账号凭据,放哪儿都要当密钥对待。
部署这件事,做对一次不难,难的是下次别人照着做也能对。所以这次改动都进了仓库,命令都写进了文档——包括上面这些坑。