三个月前,我看了眼支付宝账单,光服务器续费就划走了 998 元。那台 4C8G 的云主机,为了扛住一天不到 200 的 UV,已经陪我烧了两年钱。
说实话,这账怎么算都不划算。
Day 1 我做了个决定:要么彻底关站,要么把成本打下来。最后我选了后者,用 Nuxt 3 重写前端,Cloudflare Pages 托管,加上 R2 存图片,成本从每月 998 元干到 5 元。
月 5 元,不是笔误,是 Cloudflare 的 R2 存储费——10GB 以下免出口流量,我超了一点点,按 0.15 美元/GB 月计费,折合人民币约 5 元。
为什么是 Nuxt 3,不是 Next.js 也不是纯静态
我上一版站是 Vue 2 + 自建 API,前后端分离,但 SEO 一直半死不活。Google 收录 37 页,百度更惨,9 页。原因我清楚:客户端渲染,蜘蛛进来全是空壳。
换 Next.js 也想过,我团队里有人用 React 写了八年,但个人站要重学 App Router,还要处理 React 生态的版本地狱。我们评估了一下,迁移成本至少 14 天全职工时。
Nuxt 3 不一样,它用 Nitro 引擎,天生支持混合渲染。你可以在同一个页面里,对未登录用户输出静态 HTML,对登录用户走 SSR。
数据对比:我用相同内容分别渲染 100 次,Nuxt 3 的 TTFB 平均 212ms,Next.js 14 是 245ms。差距不大,但 Nuxt 3 的配置简单 40%,不需要额外配 rewrites。
回头看,选 Nuxt 3 最大理由是它和 Cloudflare Pages 的兼容性。Nitro 官方支持 preset: 'cloudflare_pages',构建后直接生成 _worker.js,不需要额外的适配层。Next.js 也有适配器,但坑多,后面会讲。
架构拆解:静态 + SSR + 边缘函数
我不需要 100% 动态。我的站有 4 种内容类型:
- 博客文章:每周 2-3 篇,基本不变
- 订阅管理:用户登录后可见,动态
- 评论系统:实时写入,动态
- 简历页:半年不变
按照 Cloudflare 的免费层,Pages Functions 每天 10 万次请求,静态资源不计数。我的全站月 PV 约 8 万,静态页面占 92%,动态请求集中在评论和订阅,每天约 1500 次。
Day 7 我确定了最终架构:
- 博客文章和简历页走静态生成(SSG),构建时拉取内容
- 订阅和评论走 SSR,用
useAsyncData请求 API - 登录态用 Cloudflare KV 存 session,过期时间 7 天
这个架构的妙处在于,Pages 会把静态文件部署到全球 300 个边缘节点,而动态请求只在最近节点执行函数。
踩坑记录:三个让我熬夜到凌晨 3 点的坑
坑一:Prisma 在边缘环境跑不起来
Day 3 我尝试用 Prisma 连接 Postgres 存评论数据,本地开发一切正常。部署到 Cloudflare Pages 后,Functions 运行时直接报错。
困惑:本地好好的,生产环境就是 Error: PrismaClient is unable to be run in edge runtimes。
搜了一天,找到答案:Pages Functions 默认跑在 V8 isolates 里,不支持 Prisma 的二进制引擎。解决办法有两个,换掉 ORM,或改用 D1(Cloudflare 的 SQLite)。
我选了 D1,因为免费额度 5GB 存储,且和 KV 一样免维护。
D1 的坑不比 Prisma 少。SELECT * FROM comments WHERE post_id = ? 这种最简单的查询,第一次执行竟然要 400ms。后来发现是冷启动,加了 preparedStatement 缓存后稳定在 12ms。
坑二:图片优化导致页面权重暴跌
上个月我把图片全部迁移到 Cloudflare Images,原因是为了省 R2 流量费。结果一周后,Google Search Console 提示 Core Web Vitals 的 LCP 从 1.8s 涨到 4.2s。
现象是页面代码里 <img> 标签的 src 变成了 CDN 地址,但每次请求都要先走 Worker 做图片变换。我用了 on-the-fly 的参数 ?width=800&format=webp,结果每个图片首次访问要等 Worker 处理完才返回。
解法:放弃 on-the-fly,改为构建时压缩。在 Nuxt 3 的 nitro 配置里加一个 hook,本地生成三种尺寸的 WebP 文件,直接放 R2。图片加载时间从 4.2s 降到 0.8s。
坑三:Pages Functions 的并发限制
第 2 周,我的站被某个技术社区转载了,当天 UV 冲到 8500。然后,订阅接口开始 500 错误。
看日志,Function invocation limit exceeded。Cloudflare 免费层的限制是每秒 1000 次函数调用。我的评论系统在高峰期每秒触发 2400 次写操作,直接打爆。
解法不是升级付费套餐,而是加缓存。我把热门文章的评论在构建时静态化,写入 JSON 文件,动态接口只处理 POST /api/comments 的实时提交。读取评论全部走静态文件,24 小时重建一次。
数字对比:三个月的实测数据
| 指标 | 旧架构 (云主机 + 自建 API) | 新架构 (Nuxt 3 + Pages) | 变化 |
|---|---|---|---|
| 月成本 (元) | 998 | 5.2 | -99.5% |
| TTFB 中位数 (ms) | 386 | 212 | -45% |
| LCP (ms) | 2100 | 760 | -63% |
| 构建部署时间 (min) | 手动 rsync,平均 15 | CI 自动,平均 3 | -80% |
| 月故障时间 (小时) | 2.4 (包含挖矿入侵) | 0 | -100% |
| 服务器 CPU 使用率 | 平均 7%,峰值 62% | 无服务器 | 不再关心 |
说实话,看到这组数据的时候我愣了几秒。不是得意,是怀疑哪里算错了。但连续跑了 30 天,成本端确实只有 R2 的超额费用 5 元,其他全为 0。
成本到底怎么算到 5 元的
Cloudflare 免费层包含:无限静态请求、每天 10 万次函数调用、KV 每天 10 万次读、D1 每天 5 万次行读取。这些都够我用。
唯一的超额项是 R2。免费层给 10GB 存储 + 每月 100 万次读操作。我的图片总量 13.7GB,超了 3.7GB,存储费 0.15 美元/GB/月,所以 0.56 美元,约合 4 块钱。再加一点读操作超额,总共 5.2 元。
如果我把图片压到 10GB 以内,成本就是 0。
不过呢,我没压,因为质量还是第一位的。而且按我现在 3 万张图片的增长速度,至少 8 个月后才会再超额度 1GB。
Nuxt 3 配置细节:三个我试过值得分享的参数
-
routeRules:把博客详情页设为swr: 3600,表示 1 小时重新验证一次。我试过ssr: false,那等于回到纯客户端渲染;也试过static: true,但文章修改后要重新构建。SWR 是折中最优解。 -
nitro.prerender.crawlLinks:打开后会自动抓取站内所有链接并静态化,省掉手动维护路由列表。我跑了一次,自动预渲染了 487 个页面。 -
build.transpile:如果你们用了某些老库(比如我用的一个 markdown 解析器),不加这个配置,构建产物会报错的。这个我花了 3 天踩坑。
但我也要承认 Nuxt 3 + Cloudflare 不如 传统主机 的地方
第一,调试体验差。传统主机上你 ssh 进去,tail -f 日志,什么都在眼前。Cloudflare Functions 的日志要到仪表盘看,每条调用延迟 30 秒。而且本地调试和线上行为有差异,尤其是 KV 的一致性。我遇到过线上读到旧值,本地永远复现不了,最后只能加 await env.KV.get(key, {cacheTtl: 0}) 强制穿透。这点比不上直接在服务器上 redis-cli 看一眼。
第二,构建时间有变长的趋势。Day 1 构建 2 分钟,现在 200 篇文章后需要 5 分钟。如果内容量再翻 10 倍,构建可能要 20 分钟。传统主机不需要构建,直接跑代码就行。
第三,长期成本的不确定性。Cloudflare 免费层已经持续了很多年,但没人保证永远免费。万一哪天调整策略,把 Functions 改成按秒计费,我的成本会瞬间涨到 80 元/月。而自建服务器,成本是确定的。
第四,锁仓风险。我现在的内容数据库在 D1(Cloudflare 的 SQLite 变体),照片在 R2,代码是 Nuxt 3。要是想迁回自建,需要重写数据库层,还要导出 13GB 的 R2 文件,加上换用别的渲染方式。整体迁移成本,我估算了一下,大约是 5 个工作日。自建主机没这问题,搬走就是 scp -r。
我们团队最后做了什么
第 6 周,我们把同样的架构复制到了另外两个项目上。一个内部工具站,一个客户门户。成本合计 9 元/月,之前这两个项目光容器服务就要 420 元。
我并不是说所有站都适合这种方案。如果你的接口有强一致性要求,或者需要处理 WebSocket,Cloudflare 的免费层就捉襟见肘。我的站没有这些需求,所以才能把成本压到极致。
回头看,那个 998 元/月的时期,服务器实际处理的有效请求不到十分之一。现在用 5 块钱买到了更好的性能,这不是技术胜利,是认知问题:你总以为复杂系统需要昂贵的载体,直到你被迫用 5 块钱重新设计一次。
如果你也在跑个人站,看看账单里那 998 元,你确定每一分都花得有价值吗?