背景:为什么要迁回国内

博客最初部署在 Netlify,国内访问有几个硬伤:评论后端偶尔加载慢、图片走海外源站体验差,还有一个合规问题——用已备案的国内域名解析到境外服务器,并不符合 ICP 备案管理要求。虽然只是个人博客,但既然要做长期维护,早晚都要将站点放到国内。

目标是:主站跑在国内服务器,图片走国内对象存储,评论后端自建在国内,全流程备案合规。

时间线:域名、备案、服务器与迁移

顺序阶段说明
1购买域名与服务器腾讯云新客活动,一年几十块
2提交个人 ICP 备案腾讯云初审 + 管局审核,前后约两周
3整站迁移图片、评论、主站一次性切完,约半天

博客还没正式推广,没有评论数据要迁,旧 Netlify 站点也继续跑着做备份,并无迁移压力。

基础设施:域名、服务器与 ICP 备案

域名

主域名为 lblog.com.cn,评论子域名为 comments.lblog.com.cn,都在腾讯云注册和管理。

服务器

腾讯云轻量应用服务器新客专享型实例:

配置项参数
CPU2 核
内存2 GB
系统盘SSD 50 GB
流量包300 GB/月
带宽4 Mbps

服务器会分配一个公网 IP(49.233.x.x)。腾讯云新客购买和首次续费同价,一年几十块。

备案

域名购买后两天提交个人 ICP 备案。腾讯云会先初审,大概两天左右,期间会打电话确认信息;初审通过后提交管局,管局审核时间约十天(具体以当地管局为准)。备案期间旧站点继续跑在 Netlify,没有中断访问。

备案时站点名称审核比较严格,不能带”博客""个人”这类通用词。建议按官方命名规范填写,避免不符合要求。

公安联网备案

ICP 备案通过后还有一步:公安联网备案。建议也都一并申请备案也更加合规。ICP 备案管的是”这个域名能不能用”,公安联网备案管的是”这个网站是谁在运营”,两者都要做,不是可选项。

流程比 ICP 备案简单:ICP 备案通过后,备案平台会给你一个公安联网备案数据码(30 天内有效,过期要重新获取)。拿着数据码,登录全国互联网安全管理服务平台(beian.mps.gov.cn),注册账号后按提示绑定数据码、补充服务商信息,提交审核即可。

审核通过后会拿到一个「XX 公网安备 00000000 号」格式的公安备案号,和 ICP 备案号一样要展示在站点页脚,并链接到公安备案平台。

DNS 与 SSL:解析和证书

DNS 解析

在腾讯云 DNSPod 里配了三条 A 记录:

主机记录记录类型记录值
@A49.233.x.x
wwwA49.233.x.x
commentsA49.233.x.x

主站和 Waline 评论后端共用一台服务器,通过不同域名和 Nginx 反代分流。

SSL 证书

宝塔面板里一键申请了 Let’s Encrypt 免费 SSL 证书,主站和 comments.lblog.com.cn 子域都开了 HTTPS。

图片加速:从 R2 到腾讯云 COS

建桶

在腾讯云 COS 控制台创建存储桶:

项目参数
存储桶名称lublog-images-<APPID>
地域北京(ap-beijing)
访问权限指定用户
当前存储量约 90 MB

后端适配

src/lib/storage.ts 里已经预留了 COS 后端,和 Cloudflare R2 复用同一套 AWS S3 SDK。只是 endpoint、region 和 forcePathStyle 不同:

  • COS:cos.ap-beijing.myqcloud.com,forcePathStyle=false
  • R2:<accountId>.r2.cloudflarestorage.com,forcePathStyle=true

代码层配置好 COS_SECRET_ID、COS_SECRET_KEY、COS_BUCKET、COS_REGION、COS_PUBLIC_URL 后,存储后端就切过去了,业务代码零改动。图片 URL 继续走签名 URL,原 R2 的私有化逻辑在 COS 上同样适用。

数据迁移

图片迁移用项目里的脚本完成:npm run migrate:r2-to-cos。

脚本会读取 MongoDB 里 gallery_images 实际引用的 storageKey/thumbKey,只搬这些对象(R2 里共 260 个对象,画廊只引用其中一部分),流式从 R2 get 到本地再 put 到 COS。全部成功后,批量把 store 里的 url/thumbUrl 域名前缀从 R2 换成 COS;中途若有失败项则不改 store,避免指向没迁完的 COS。

迁移后旧 Netlify 站点和原 R2 桶保留,旧方案有足够的免费额度,也不必担心双桶重复计费或提前停机。

评论后端:Waline 从 Vercel 到自建容器

部署方式

Waline 后端从 Vercel + Neon Postgres 迁回国内服务器,用 Docker 容器部署:

  • Web 服务:waline:latest,端口 8360
  • 数据库:MariaDB 10

容器编排文件放在宝塔 /www/docker/waline/docker-compose.yml 下。

数据库选型波折

一开始尝试过旧方案的 Postgres,后来想更轻量化用 SQLite,结果首次注册管理员时报错提示缺表。最后选了 MariaDB,稳定可用。

建表

在宝塔文件管理器里把 Waline 官方建表 SQL 上传到 /www/docker/waline/waline.sqlite.sql,包含评论表、表情反应计数器表、用户表三张核心表,手动执行完成初始化。

反代

Nginx 把 comments.lblog.com.cn 反代到本机 8360 端口。防火墙不需要对外开放 8360,外网只通过域名和 HTTPS 访问。

主站部署:宝塔反向代理 + Astro node standalone

Astro 配置已经从 @astrojs/netlify 切到 @astrojs/node standalone 模式。构建产物是一个 Node 服务,宝塔里建网站后做反向代理即可。

首次配置:在宝塔网站里添加反向代理,指向 http://127.0.0.1:4321(Astro node standalone 服务默认监听端口),配置一次即可。

之后每次更新站点:

  1. 服务器上拉取最新代码
  2. npm ci 安装依赖
  3. npm run build 构建
  4. 重启 Node 服务

目前站点还没正式推广,构建频率不高,没有专门写自动部署脚本,手动执行足够。

经验与教训

  1. 备案通过前域名不能指向国内服务器:管局审核未完成,域名就无法正式解析到国内 IP。旧 Netlify 站点继续跑,可以平稳过渡。

  2. 数据库选型按场景来,别追”专业”:一开始想用 Postgres,最后选了 MariaDB。回头看,选型应该看这几点:

    • 数据规模:个人博客评论量很小,单机文件型数据库完全够用,MySQL/Postgres 的优势要到更大数据量和并发才体现
    • 服务器资源:2 核 2G 的轻量服务器,为一个评论后端跑完整 Postgres 实例属于浪费内存,MariaDB 更轻

    结论:小场景优先选”够用且自己能排查”的方案,不要因为某个数据库更”专业”就选它。

  3. 容器编排文件要放到固定路径:第一次在宝塔 Docker 容器编排上传后,在文件管理器里找不到目录,后来又重新又建了一套 /www/docker/waline,建议一开始就指定好持久化目录。

  4. 反代端口要记牢:主站和 Waline 共用一台服务器,靠域名和端口区分,配置时别写错后端地址。

  5. 迁移前先确认有没有数据要迁:本站没有评论、没有注册用户,所以数据库从 Postgres 换到 MariaDB 没有数据迁移负担。如果有相关数据,这一步必须提前规划。