← 返回博客

Astro 迁移阿里云 ECS 实施方案

从双目标构建、私有预发布到正式 HTTPS 切流的分阶段方案、验收标准与回滚边界。

2026-09-12 约 16 分钟读完

补记于 2026-09-12 · 阶段三完成,阶段四已切流并进入稳定性观察

本文目录 跳到想读的章节
  1. 1 当前结论
  2. 2 技术栈决策
  3. 3 总体架构
  4. 4 阶段总览
  5. 5 阶段 0 盘点与冻结基线
  6. 6 阶段 1 双目标 Astro 构建
  7. 7 阶段 2 ECS 私有预发布
  8. 8 阶段 3 静态生产环境准备
  9. 9 阶段 4 域名与 HTTPS 切换
  10. 10 阶段 5 视觉系统与动效升级
  11. 11 阶段 6 后端与 PostgreSQL 首个闭环
  12. 12 阶段 7 自动发布与长期运维
  13. 13 配置与密钥管理
  14. 14 安全 备份与容量
  15. 15 回滚与上线清单
  16. 16 完成定义
  17. 17 技术参考

版本:2026年9月12日修订版 用途:供 Codex 按阶段执行、验收、记录和回滚

1 当前结论

站点继续采用 Astro 5、TypeScript strict、Astro Content Collections 和静态生成。设计升级以内容刊物型网站为主体,优先改进排版、图片叙事、页面转场、滚动揭示和细微反馈;沉浸式 3D 或 WebGL 专题暂不建设,出现明确内容方案后单独立项。

域名备案已经通过。纯静态站已于 2026 年 9 月 12 日切换到阿里云 ECS:https://www.doyouhang.live 是规范地址,https://doyouhang.live 保留访问;两个域名都解析到 ECS,HTTP 跳转到同主机名的 HTTPS。GitHub Pages 保留 7 至 14 天作为独立静态回退入口。

当前 ECS 为 2 核 CPU、2 GB 内存、40 GB 系统盘和 3 Mbps 公网带宽。该规格能够运行 Astro 静态站、Nginx 和 Docker Compose,也能在低访问量下增加轻量 API 与保守配置的 PostgreSQL。前端构建继续在本机或 GitHub Actions 完成,不能在 ECS 上长期执行高内存构建任务。

阶段 0 至 3 已完成;阶段 4 已完成切流和即时验收,24 至 48 小时上线观察正在进行。切流基线发布为 a75bbc7,阶段二私有预发布容器和 GitHub Pages 回退入口均暂时保留。后端、PostgreSQL 和完整自动发布不阻塞本次静态上线。

2 技术栈决策

层级当前选择后续策略
前端框架Astro 5 静态生成保留,不因设计升级迁移到 React、Next.js 或 Vue
内容系统Astro Content Collections 与 Markdown保留,文章不默认迁入数据库
样式原生 CSS 与全站设计令牌保留并逐步完善,不预先引入 Tailwind
基础动效CSS、View Transitions、ClientRouter继续使用,脚本接入现有幂等初始化机制
高级动效暂不新增运行时依赖有明确时间线或滚动编排后按需评估 GSAP
3D 与 WebGL暂不建设沉浸专题单独设计、预算和验收
静态入口Nginx 容器保留,只公开 80 与 443
容器编排Docker Compose保留 staging 与 production 独立覆盖文件
后端Node.js、TypeScript 与 Fastify仅在首个真实动态功能确定后加入
数据库PostgreSQL与首个持久化业务闭环一起加入
大型资源初期由 ECS 提供视频、3D 或流量成为瓶颈后再引入 OSS 与 CDN

技术栈重新评估条件:网站主体变成持续运行的客户端应用、全站依赖 WebGL 场景,或 Astro 的岛屿边界已经妨碍核心交互。单纯需要更精细的动画不构成换栈理由。

3 总体架构

3.1 当前静态上线链路

公众浏览器
  -> 已备案域名
  -> ECS 公网 80 或 443
  -> Nginx 容器
  -> Astro 静态构建产物

GitHub Actions
  -> 检查与构建
  -> GitHub Pages 旧站兜底

维护者电脑
  -> SSH
  -> ECS 私有预发布 127.0.0.1:8080

3.2 未来动态链路

浏览器 -> Nginx
  -> / 与静态资源 -> Astro 构建产物
  -> /api/* -> API 容器 -> PostgreSQL

前端保持静态生成,动态交互通过同源 /api 完成。只有明确需要请求时渲染时再评估 Astro SSR,不将 SSR 作为当前上线条件。API 和数据库不得发布宿主机公网端口。

3.3 仓库结构

repo/
  src/                       # 当前 Astro 站点
  public/                    # 公开静态资源
  apps/api/                  # 阶段 6 才创建
  infra/docker/              # Web 与未来 API 镜像
  infra/nginx/               # staging 与 production 配置
  infra/compose.yaml         # 基础服务,不直接发布端口
  infra/compose.staging.yaml # 只绑定 127.0.0.1:8080
  infra/compose.production.yaml
  scripts/                   # 构建、部署、冒烟和回滚工具
  docs/migration/            # 方案与阶段记录
  docs/operations/           # 运维手册
  .github/workflows/         # Pages、CI 与未来 release

Astro 保持在仓库根目录,当前没有迁移到 apps/web 的收益。真实密钥、服务器地址和环境文件不得提交。

4 阶段总览

阶段目标状态
阶段 0盘点仓库、服务器和回滚基线已完成
阶段 1同一源码支持 Pages 与 ECS 两种构建路径已完成
阶段 2ECS 回环端口与 SSH Tunnel 私有预发布已完成
阶段 3准备静态生产环境已完成(2026-09-12)
阶段 4域名、HTTPS 与正式切流已完成切流,观察中(2026-09-12)
阶段 5视觉系统与动效升级上线稳定后推进
阶段 6后端与 PostgreSQL 首个闭环有明确业务需求后推进
阶段 7自动发布、备份和长期运维分步完善

5 阶段 0 盘点与冻结基线

目标:掌握真实环境并建立可恢复基线,不改变线上入口。

已完成内容:

  1. 核对 Astro、Node、锁文件、构建命令、Pages 工作流、sitebase、输出目录和主要路由。
  2. 记录 ECS 系统、CPU 架构、内存、磁盘、端口和既有服务;敏感值未写入仓库。
  3. 验证 GitHub Pages 构建、根路径 ECS 构建、主要页面、404、RSS、sitemap 和搜索索引。
  4. 保存可回滚提交和现有 Pages 入口。

验收:干净环境可按锁文件构建;Pages 保持可访问;未知参数不以猜测值写入配置。

回退:阶段 0 不修改生产状态。

6 阶段 1 双目标 Astro 构建

目标:同一份代码同时支持 GitHub Pages 的 /blog-demo/ 和 ECS 的根路径 /

已完成内容:

  1. 使用 SITE_URL 控制规范源站,使用 SITE_BASE 控制路径前缀。
  2. Pages 工作流继续使用 SITE_BASE=/blog-demo/,ECS 镜像使用 SITE_BASE=/
  3. 内部链接继续遵循 import.meta.env.BASE_URL,并覆盖深层路由、404、RSS、sitemap 和 Pagefind。
  4. 完整构建运行 npm run build,包含字体子集和搜索索引生成。

验收:两种 base 构建与浏览器冒烟均通过,产物不能交叉发布。

回退:恢复原 Astro 配置和 Pages 构建参数。

7 阶段 2 ECS 私有预发布

目标:备案期间只通过 ECS localhost 和 SSH Tunnel 验证真实部署。

已完成内容:

  1. 安装 Docker Engine 与 Compose,建立版本化发布目录。
  2. Web 镜像只包含 Nginx、配置和 Astro dist,排除源码、密钥、.git、依赖与备份。
  3. 基础 Compose 不发布端口;staging 配置只绑定 127.0.0.1:8080:80
  4. 配置健康检查、只读文件系统、日志轮转、no-new-privileges 和重启策略。
  5. 通过 ECS 本机和 SSH Tunnel 验证首页、深层路由、资源与 404;公网访问 8080 不通。
  6. Docker Hub 不可用时采用经过校验的本地镜像传输方案,并记录替代路径。

验收与实际结果见 ECS 私有预发布搭建记录

回退:切回上一镜像,或停止容器并恢复已保留的宿主机 Nginx 配置。

8 阶段 3 静态生产环境准备

目标:在不切换 DNS 的情况下完成最终域名、TLS 和公网配置验证。

已完成内容:

  1. 确认根域名、www、规范域名和跳转关系,记录当前 A、AAAA、CNAME 与 TTL。
  2. 新增独立 production Nginx 配置和 Compose 覆盖文件,不与 staging 文件同时叠加。
  3. 因两个 A 记录已指向 ECS,使用 Certbot webroot 与 HTTP-01 申请最终域名证书;未创建或保存 DNS API 凭据。
  4. Nginx 加载完整证书链和私钥,HTTPS 提供站点,HTTP 跳转 HTTPS。证书文件不存在时不得启动引用它的配置。
  5. 配置 HTML、哈希静态资源、404、压缩、日志轮转和必要安全响应头。只有内容哈希资源使用长期 immutable 缓存。
  6. 页面展示真实备案号和官方查询链接,并核实上线后适用的公安备案要求。
  7. 使用 SSH Tunnel、本地 hosts 或 curl --resolve 验证最终域名、SNI、证书链、首页、深层路由、资源、404、RSS 和 sitemap。
  8. 检查最终 Compose 端口、宿主机防火墙、阿里云安全组和 IPv6;API、数据库和 staging 端口保持公网关闭。
  9. 记录当前发布标识、上一发布标识、配置校验值、回滚命令和预计恢复时间。

实际结果:根域名和 www 的 A 记录均为 ECS 地址,TTL 为 600 秒;没有 AAAA。Let’s Encrypt 证书覆盖两个域名,有效期至 2026 年 12 月 10 日;自动续期 timer 与 deploy hook 已启用,certbot renew --dry-run 通过。生产 Compose 只发布 IPv4 的 80 与 443,8080 保持回环绑定。最终 Host、SNI、证书链、首页、文章、404、RSS、sitemap、Pagefind、安全响应头和未知主机拒绝均已通过 ECS 本机验证。

验收:已通过。由于公共 A 记录在执行前已经指向 ECS,本次没有“保持公共 DNS 不变”的前置窗口;改用独立临时 ACME 入口签发证书,并在生产容器接管端口前完成 curl --resolve 验证。上一静态版本和 Pages 回退入口均保留。

回退:停止 production 配置并恢复 staging 回环入口,不修改 DNS。

9 阶段 4 域名与 HTTPS 切换

目标:把公开访问从 GitHub Pages 切换到 ECS 静态站。

已完成内容:

  1. 阶段 3 验收通过后冻结发布,保存 Pages、DNS 和 ECS 当前状态。
  2. 确认切换时 TTL 已为 600 秒;DNS 回切不会瞬时完成。
  3. 启用 production Compose,开放阿里云安全组与主机防火墙的 80、443;SSH 继续限制来源。
  4. 因两个 A 记录已提前指向 ECS,先用 curl --resolve 对容器做最后检查,再让生产容器接管 80 与 443。IPv6 全链路未验证,因此不设置 AAAA。
  5. 使用多个解析器和真实浏览器验证首页、文章、搜索、资源、404、RSS、sitemap、HTTPS、HTTP 跳转及移动端。
  6. 检查 Nginx 状态码、5xx、容器重启、CPU、内存、磁盘和公网带宽。
  7. 已开始 24 至 48 小时观察;GitHub Pages 保留 7 至 14 天作为独立静态兜底入口。
  8. 备案信息、证书续期和 DNS 最终值写入脱敏运维记录。

实际结果:生产 Compose 项目固定为 blog-demo-production,容器 blog-demo-production-web-1 运行镜像 blog-demo-web:a75bbc7,健康检查通过且零重启;/opt/blog-demo/current 已指向 /opt/blog-demo/releases/a75bbc7。公网两个域名 HTTPS 返回 200,HTTP 返回 308,文章、搜索、Pagefind、RSS 和 sitemap 返回 200,未知路径返回 404,公网 8080 连接超时。Chrome 直接访问公网域名时,桌面和 390px 手机宽度均无横向溢出,成功页面没有脚本或控制台错误。上线验收时未发现 5xx,容器内存约 4 MiB,根盘使用率 19%。原有 SSH、frps 和 AI 网关监听未改动。

验收:切流验收已通过,24 至 48 小时稳定性观察仍在计时。GitHub Pages 的首页与深层文章返回 200,提交 a75bbc7 的 Pages 工作流成功,可承担独立静态回退。

回退:GitHub Pages 默认地址已验证,但本次开始执行时两个 A 记录已经指向 ECS,未观察到更早的自定义域名记录,因此不能把未知旧值写成回切目标。首次生产版本故障时保留 ECS 现场并发布 Pages 默认地址;以后存在已验收的上一生产镜像后,优先在同一 ECS 回退镜像,减少 DNS 缓存带来的双入口时间。

10 阶段 5 视觉系统与动效升级

目标:在生产入口稳定后,把站点升级为以内容刊物为主体、动效服务于阅读的个人档案。

任务:

  1. .better-web-ui.md 为设计上下文,先统一排版、栅格、留白、图片比例、明暗主题和响应式规则。
  2. 延续纸色、墨色、藏青、朱红和三层字体体系;设计感来自排版、内容证据和精确反馈。
  3. 第一层使用 CSS、View Transitions 和现有 ClientRouter,实现页面转场、共享元素、滚动揭示、图片进入和导航反馈。
  4. 只有明确出现时间线编排、复杂滚动同步或 SVG 序列需求时才评估 GSAP,并按页面拆包加载。
  5. 沉浸专题、Three.js、WebGL、背景视频和大型模型不纳入本阶段;未来作为独立需求评估性能、资源和降级方案。
  6. 所有动画支持 prefers-reduced-motion;触摸设备不依赖 hover;低性能设备可以获得静态但完整的内容。
  7. 初始性能目标:主页首次传输约 800 KB 以内,普通文章约 1 MB 以内;以真实构建和浏览器测量为准,不为数字牺牲必要内容。
  8. 当前 3 Mbps 带宽下优先压缩图片、按需加载和合理缓存。出现视频、3D 或持续流量瓶颈后,再评估 OSS 与 CDN 的成本和接入。

验收:内容在无脚本、窄屏和 reduced-motion 下完整可读;视觉回归通过;普通页面不加载未使用的高级动效库;实际加载体积没有明显倒退。

回退:关闭新增动效入口并恢复上一静态镜像;内容和路由不依赖动画才能访问。

11 阶段 6 后端与 PostgreSQL 首个闭环

目标:只围绕第一个明确业务功能建立 API 与持久化能力。

入口条件:用户已确定真实功能、数据所有者、读写权限、公开范围和成功标准。没有业务需求时不创建示例数据库功能。

任务:

  1. 创建 TypeScript 与 Fastify 服务,分离路由、业务逻辑、数据访问和配置校验。
  2. 统一 /api 前缀,提供存活与就绪检查;API 在容器网络监听 3000,但不发布宿主机端口。
  3. Nginx 同源反向代理 /api,不默认开放通配 CORS。静态页面在 API 故障时仍可阅读。
  4. 请求使用 schema 校验、统一错误体、请求 ID、结构化脱敏日志、大小限制、超时和优雅退出。
  5. PostgreSQL 只接入 internal data 网络,不写 ports;管理员、迁移任务和应用使用不同身份,应用不使用超级用户。
  6. 迁移文件随代码版本化,由一次性任务执行;应用启动时不争抢 DDL,也不自动清库。
  7. 2 GB 内存下使用小连接池和保守数据库配置,持续观察系统余量。图片处理、全文索引、后台任务或持续内存压力出现时,优先升级到 4 GB。
  8. 为首个功能覆盖正常读写、非法输入、重复数据、事务失败、重启保留和数据库断开降级。
  9. 建立加密异地备份并向隔离数据库完成一次恢复;只有备份文件而没有恢复验证不算完成。

验收:API 不可被公网绕过 Nginx 直连;权限与输入验证有效;容器重建不丢数据;恢复演练成功;数据库故障不影响静态内容。

回退:关闭动态功能,恢复兼容当前 schema 的上一组 Web 与 API 镜像。禁止自动执行破坏性降级或 docker compose down -v

12 阶段 7 自动发布与长期运维

目标:把已经验证的人工步骤固化为可追踪、可回滚的发布流程。

任务:

  1. 保留 GitHub Pages 工作流作为过渡期旧站和回退入口。
  2. 新增 CI,对锁文件安装、Astro 检查、单元测试、构建、浏览器冒烟和未来 API 测试进行验证;PR 不获取部署凭据。
  3. 发布工作流构建一次,以提交 SHA 标记镜像并记录不可变摘要。先手动触发,稳定后再评估自动生产发布。
  4. ECS 默认通过受控出站方式拉取发布清单和镜像,不为 GitHub 公网 Runner 放开任意来源 SSH。
  5. 部署器先校验来源、摘要、架构、配置、磁盘和所需密钥,再获取部署锁、拉取镜像、更新服务并执行健康检查。
  6. 健康检查失败时恢复上一份发布清单;数据库迁移存在时遵守 schema 兼容规则,不能仅回退应用而忽略数据结构。
  7. Docker 日志设置大小和保留上限,旧镜像和临时产物按发布记录清理;40 GB 磁盘在 80% 使用率前告警。
  8. 监控 CPU、内存、磁盘、容器重启、5xx、证书到期和备份失败。证书续期后先执行 Nginx 配置检查,再重载并验证新证书。
  9. 数据库上线后每日生成逻辑备份,发布前额外备份;备份加密后传到独立存储,并定期执行隔离恢复。

部署执行契约:

1 校验发布来源、镜像摘要、架构、配置与密钥
2 获取部署锁,保存当前发布清单,检查磁盘
3 拉取全部镜像,失败则保持当前版本
4 检查 Compose 最终配置和预期端口
5 有数据库变更时创建并验证发布前备份
6 运行一次性迁移任务,失败则停止
7 更新服务并等待有时限的健康检查
8 检查首页、资源、深层路由、API 与业务读写
9 成功后更新 current 和发布记录
10 失败时按兼容规则恢复上一镜像组合

验收:成功发布可追踪;失败构建不部署;镜像拉取失败保持原站;健康检查失败可回退;日志和备份不会耗尽磁盘。

13 配置与密钥管理

环境至少分为本地开发、ECS 私有预发布和生产。预发布与生产配置不得混用。

  • 构建期公开配置:SITE_URLSITE_BASE、未来的 PUBLIC_API_BASE 和公开功能开关。修改后必须重新构建。
  • API 运行配置:NODE_ENVPORT、数据库主机、数据库名、应用用户、日志级别和功能开关。
  • 密钥:数据库密码、会话签名密钥、镜像仓库凭据、DNS API 凭据和备份加密密钥。
  • 密钥不得通过客户端 PUBLIC_ 变量、Docker ARG、镜像层、命令行明文或代码文件传递。
  • 推荐从受保护文件挂载 Compose secrets;源文件本身仍需正确的属主和权限。
  • .env.example 只保留键名和无密钥示例,真实环境文件同时加入 .gitignore.dockerignore
  • CI 只获得推送镜像所需权限;数据库与会话密钥保留在 ECS。日志不得打印完整连接串、Authorization、Cookie 或个人数据。
  • 轮换顺序为创建新凭据、更新消费者并验证、撤销旧凭据、记录版本与时间。

14 安全 备份与容量

14.1 服务器

  • SSH 使用密钥并限制来源;验证替代登录成功后再禁用不需要的密码和 root 登录。
  • 公网只开放计划内的 80 与 443,API、PostgreSQL 和 staging 端口保持私有。
  • 定期更新系统和容器基础镜像,记录变更并保留上一版本。
  • 写接口上线前必须完成身份认证或匿名防滥用设计、授权、输入校验、速率限制和 CSRF 或 Origin 防护。
  • Cookie 会话使用 HttpOnly、Secure 和适当的 SameSite;SQL 必须参数化。

14.2 容量

  • 不在 ECS 上执行常规前端构建,避免 2 GB 内存被安装和打包任务耗尽。
  • Docker 镜像、容器日志、数据库、备份和系统更新共同使用 40 GB 系统盘,达到 80% 前告警。
  • 当前 3 Mbps 足以服务优化后的个人静态站,但多个访客会共享带宽。大型媒体出现前先测量,不预先购买 OSS/CDN。
  • 若持续出现内存交换、OOM、数据库连接等待或后台任务竞争,升级到至少 2 核 4 GB。

14.3 PostgreSQL 备份

初始目标为 RPO 24 小时、RTO 2 小时,需由恢复演练验证。

  1. 每日使用匹配数据库版本的 pg_dump -Fc 创建逻辑备份,发布前额外备份。
  2. 临时文件完成且命令退出码为零后,使用 pg_restore --list 检查,再计算校验值、加密并上传异地存储。
  3. 建议保留每日 7 份、每周 4 份、每月 3 份,并为存储配置生命周期和删除保护。
  4. 至少每月向全新隔离数据库恢复,检查角色、迁移版本、代表性数据和读写。
  5. ECS 快照可以辅助灾难恢复,但不能替代验证过的数据库备份。

15 回滚与上线清单

15.1 切换前

  • 备案通过,备案号和展示要求已经落实。
  • 阶段 0 至 3 验收完成;当前生产版本可重建,Pages 独立静态回退已验证。
  • 最终域名、www、A、AAAA 和 TTL 已记录;两个域名都保留,不设置 AAAA。
  • TLS 域名匹配、完整证书链、续期路径和失败处理已验证。
  • 使用最终 Host 与 SNI 完成切流前检查。
  • Compose 实际端口、IPv6、安全组和防火墙已核对。
  • GitHub Pages 默认地址已验证,能够承担短期静态回退。

15.2 切换时

  • 冻结发布并记录发布标识。
  • 启用 production 配置,只为博客发布 80 与 443。
  • --resolve 验证新 ECS,并确认两个 A 记录均指向 ECS。
  • 用真实域名检查首页、文章、资源、404、RSS 和 sitemap。
  • 验证 HTTPS、HTTP 跳转和双域名关系,不存在 Pages 路径前缀残留。
  • 检查日志、5xx、容器状态、内存、磁盘和带宽。

15.3 切换后

  • 观察 24 至 48 小时,记录异常和实际发布版本。
  • 验证证书续期任务;到期告警留待阶段 7 自动监控。
  • 保留 GitHub Pages 7 至 14 天,确认无需回退后再决定是否停止。
  • 清理临时端口、测试凭据和不再需要的镜像。
  • 更新搭建记录与运维手册。

静态入口故障时,有已验收的上一生产镜像则优先在 ECS 内回退;当前首次生产版本没有可用的上一生产镜像,应保留现场并使用已验证的 GitHub Pages 默认地址提供静态回退。未来引入数据库后,Pages 只能提供静态降级,不能形成第二套写入口。

16 完成定义

静态迁移完成:正式域名通过可信 HTTPS 稳定提供站点;主要页面、资源、404、RSS 和 sitemap 正常;公网边界正确;发布有记录且可以回退。

设计升级完成:页面保持可读、可访问和可降级,动效按页面加载,真实体积和浏览器回归满足项目约束。

动态能力完成:API 权限明确,PostgreSQL 可恢复,部署与 schema 兼容,故障不会破坏静态阅读入口。

“DNS 已修改”“容器正在运行”或“生成了备份文件”都不足以单独判定对应阶段完成。

17 技术参考

以下官方资料在执行相关阶段时应再次核对版本与规则:

读到这里,谢谢你的时间。

如果还想继续读下去,
新的文章和闪念会送进 RSS。

订阅这本档案 ↗