Next.js + PayloadCMS 阿里云 ECS 容器化部署
可以通过访问 https://daolanx.fun 看效果:

这是一个部署在国内的具备 CMS 管理后台的网站,为了降低合规难度前台展示做了简化,但整体是一个完整的 CMS 图文编辑和展示能力。
类似的产品形态,在海外可以通过 Vercel 部署 + Cloudflare 域名管理轻松实现。但如果要部署在国内,上述选型会存在访问速度和合规问题。目前我选择以阿里云 ECS 作为运行环境,OSS 做图片和数据存储备份,应用层使用 Next.js + PayloadCMS,配合 SQLite 作为数据库,最后通过 Docker 打包来完成部署。该方案的主要目标是:在国内实现同样的 CMS 产品能力,同时保证性能与合规符合要求,并且从交付角度尽量保持简单,资费尽量便宜。
1. 选型思考
1.1 为什么 ECS 是必选项
通常来说建议优先选择 ECS 作为运行环境。它可能不一定是技术上的最优解,但主要考虑国内的备案合规因素,ECS 是审核中最常见且最容易通过的方案。还有一些运行环境(例如 Serverless 函数计算服务)其实也能实现网站托管,但在备案资质和审核方面,由于形态不太常规,可能会遇到一些卡点。
1.2 为什么 OSS 是必选项
因为 CMS 内容会涉及大量的图片、媒体和文件,将其存储在 OSS 而不是本地,能大大提升数据安全性。同时,可以利用 CDN 的特性加速资源的访问速度,并借助边缘计算能力实现响应式图片等高级功能。
1.3 为什么选择 SQLite 而不是 PostgreSQL
通常使用 PayloadCMS 方案时,官方一般推荐配合功能更强大的 PostgreSQL。虽然阿里云 RDS 也支持 PostgreSQL,但实测下来,国内和海外的主要区别在于:海外有许多免费的数据托管服务,而国内的数据服务基本都是收费的。强制上 RDS 会增加不必要的开销,且当前的站点规模往往用不上那些高级特性。相比之下,SQLite 刚好能完美适配 PayloadCMS,不仅管理简单,还能很方便地通过定期上传 OSS 来实现数据备份。
1.4 为什么采用 Docker 部署
是以 Docker 容器形态还是直接以代码库形态部署,对于纯个人开发来说可能差异不大。但如果你是作为技术服务方将方案交付给客户,以 Docker 镜像形态交付会更加标准化。此外,借助阿里云 ACR(容器镜像服务),可以非常方便地进行容器和版本管理。相比直接部署代码库,这能大幅度降低项目的交付和运维成本。
1.5 为什么使用宝塔面板
环境的安装和日常运维确实可以通过纯命令行和脚本来执行。引入宝塔面板主要是为了操作更加直观,从客户交付的角度来看界面更友好,且符合国内很多站长的使用习惯,属于因地制宜的考量。
2. Docker 配置设计
我最早的方案是让 Docker 镜像内置尽量完整的服务:即同时包含 Next.js 应用和 Nginx,并通过挂载数据卷的方式关联 SQLite 的数据库文件。发现构建时间长体积大,调试困难。
后来觉得,其实保持简单才是最重要的,最终改为使用宿主机外部的 Nginx 服务来进行反向代理,并去掉了复杂的数据卷挂载逻辑,一切都变得简单明了。
3. 构建与部署流程设计
构建和部署是不可或缺的环节,但在“哪里构建、怎么部署”这个问题上,我也迭代了几个版本。
最早的设计是模仿 Vercel 的提交即自动部署:通过 GitHub Actions 实现提交代码后自动完成 ECS 初始化、代码构建、镜像推送以及部署到 ECS 的全流程。但实测发现,这个 Action 流程太重了,执行时间长且稳定性不高,而且通过 CI 直接登录 ECS 也带来了一些安全风险和额外的维护成本。
后来优化为:在 CI 阶段,仅基于 Git Tag 来触发镜像构建并上传到镜像仓库;而最终的部署动作则改为手动执行。感觉这样的分离设计更符合实际的开发习惯,也更能满足生产环境对稳定性的诉求。
最后剩下的问题是:ECS 的环境初始化和部署脚本应该在哪执行?虽然在本地跑脚本远程操控也可以实现,但考虑到交付的便利性,最终的选择是将部署脚本打包拷贝到 ECS,直接在 ECS 宿主机上执行初始化和部署动作。
总结一下:构建与部署分离,所有关于 ECS 的操作都在 ECS 本地执行,这样的架构最简单清晰。
4. 其他踩坑记录
在实操过程中还遇到了不少坑,例如 Next.js 以 standalone 模式构建时尝试连接数据库报错、PayloadCMS 生产环境下数据不会触发自动同步导致无法登录,以及 SQLite 的文件权限问题等。这些问题的解决过程我都记录在 README.md 里面了。