一天交付两个站的完整基础设施——从域名对调到全自动部署

起点

两个个人品牌站,各绑一个域名,跑在同一台阿里云轻量服务器上。用了快一年,发现域名和内容定位对不上——A 站更适合 B 域名,B 站更适合 A 域名。

这事拖了半年没动。因为”换个域名”听起来简单,实际涉及的环节比想象的多:DNS、SSL 证书、反向代理配置、构建产物里注入的 canonical URL、sitemap、OG 标签、robots.txt、页脚互链……改一个漏一个,上线就出 bug。

7 月 6 号凌晨三点半,终于决定一口气干完。

时间线

03:30 开工。先确认域名映射关系,画了一张对照表贴在屏幕边上。这一步后来救了命——中间至少三次差点搞反。

04:00 - 06:00 改 Caddyfile。两个域名块对调 root 路径。发现 Caddy 的 domain.com {} 写法自动启用 HTTPS,但 domain.com:80 {} 强制 HTTP。之前某个域名绑了 :80,所以一直没证书。去掉端口绑定,Caddy 自动申请 Let’s Encrypt 证书。

06:00 - 07:00 SSL 证书生效,两个站都能 HTTPS 访问。但其中一个站返回 403。排查发现目录权限是 700(macOS umask 推过去的),Caddy 用户进不去。chmod -R 755 解决。子目录 images/ 也是 700,图片全部 403。递归修。

07:00 - 09:00 修构建产物里的旧域名残留。astro.config.mjssite 字段还是旧域名,导致所有页面的 canonical URL、og:url、JSON-LD、sitemap 全部指向错误的站。同时检查 robots.txtog-default.svg 里的硬编码域名。改完重新 build,grep 扫描 dist/ 确认零残留。

09:00 - 11:00 搭 GitHub Actions 自动部署。两个站各写一个 workflow:push → npm ci → build → scp dist/ 到服务器 → chmod。踩了两个坑:(1) SERVER_HOST 填了内网 IP,GitHub runner 连不上;(2) 大仓库在服务器上 git clone 超时,改成在 runner 上 build,只传 dist/。

11:00 - 13:00 SSH 从 Mac 连不上服务器的 22022 端口(运营商拦截)。用 GitHub Actions 绕过——反正自动部署已经配好了,不需要本地 SSH。git push 走 SOCKS5 代理。

13:00 - 16:00 新栏目上线。给其中一个站加了”每周书目”板块:Astro 内容集合、封面图本地托管(从 Open Library 下载到 public/images/books/)、列表页+详情页模板、去重索引。从 EPUB 文件提取内容,清理格式,构建验证通过。

16:00 - 18:00 全站检查。逐个栏目点进去看,发现页脚互链指向了错误的站。修。史料页的卡片列表缺少新栏目的入口,加上。“最近更新”混进了不属于这个板块的随笔,去掉。每改一处就 push 一次,GitHub Actions 自动部署,curl 线上 URL 确认内容已变。

18:00 - 20:00 收尾。写了技术博客和教训文档。检查所有文章的引号格式(直引号→弯引号)。确认两站完全隔离,没有任何交叉引用泄露。

交付清单

交付物状态
域名对调(两个域名互换绑定)完成
SSL 证书(两个站都启用 HTTPS)完成
Caddy 双站配置(反向代理 + 自动 HTTPS)完成
GitHub Actions 自动部署(push 即上线)完成
新栏目上线(每周书目,含封面图本地托管)完成
隐私隔离(两站零交叉引用)完成
技术博客 + 教训文档完成

技术栈

  • 服务器:阿里云香港轻量应用服务器,Ubuntu 24.04
  • Web 服务器:Caddy v2.11.4(自动 HTTPS,配置比 Nginx 简洁得多)
  • 构建:Astro v6(需要 Node.js >= 22.12.0)
  • 部署:GitHub Actions → scp-action → chmod
  • 代理:SOCKS5 代理走 git push

花了多少

服务器月费 34 元。两个域名年费合计约 80 元。GitHub Actions 免费额度足够个人站使用。整个基础设施的月均成本不到 40 元。

但真正花的是时间:16 个小时。如果提前把踩坑清单理出来,估计 4-6 小时就够了。所以这篇文章本身就是那个清单。

一句话总结

基础设施这种事,不难,但碎。一次做对的关键不是技术多牛,是有一张完整的检查清单,改一处验证一处。