用 Cloudflare 免费搭一个个人博客

想搭个人博客这件事拖了很久。不是没有想过,而是每次评估一圈下来都觉得麻烦:买服务器要花钱,用现成的平台又有各种限制,域名备案的事情也不想碰。后来我发现 Cloudflare 的免费套餐其实够用,加上 Astro 的静态站点方案,整件事的成本可以压到只剩一个域名费用。

选什么框架

博客的需求很简单:写 Markdown,渲染成页面,部署出去。满足这个条件的框架不少,Hugo、Jekyll、Next.js、Nuxt,都能做。

我最后选了 Astro。原因主要有两点。第一,Astro 默认就是静态优先的,生成出来的 HTML 基本上不带多余的 JavaScript,页面加载很快。第二,它支持 MDX,意味着我可以在文章里嵌组件,虽然目前还没用上,但留着不碍事。

Astro 官方有一个博客模板,直接用这个起手:

pnpm create astro@latest -- --template blog

跑完之后目录结构就出来了,博客文章放在 src/content/blog/ 里,每篇文章是一个 .md 或者 .mdx 文件,frontmatter 里写 titledescriptionpubDate 这几个必填字段。

部署到哪

Cloudflare 有两个产品可以部署静态站点:Pages 和 Workers。

Pages 更简单,连上 GitHub 仓库之后,每次 push 自动触发构建和部署,不需要自己配 CI。Workers 更底层,可以跑自定义的服务端逻辑,但配置稍微麻烦一点。

如果只是纯静态博客,Pages 完全够了。我最后选了 Workers,主要是因为之后想在博客里加一些动态功能,比如文章浏览计数或者评论,提前用 Workers 省得以后迁移。

两个方案的免费额度都很宽:

  • Pages:每月 500 次构建,带宽不限,自定义域名免费
  • Workers:每天 10 万次请求,CPU 时间 10ms/请求,对博客来说完全用不完

配置 Workers 部署

Astro 要部署到 Workers,需要装 @astrojs/cloudflare 适配器:

pnpm add @astrojs/cloudflare

然后在 astro.config.mjs 里启用它:

import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server',
  adapter: cloudflare(),
  site: 'https://yourdomain.com',
});

再在项目根目录建一个 wrangler.jsonc,告诉 Cloudflare Workers 怎么运行这个项目:

{
  "name": "my-blog",
  "compatibility_date": "2025-01-01",
  "main": "./dist/_worker.js/index.js",
  "assets": {
    "directory": "./dist",
    "binding": "ASSETS"
  },
  "environments": {
    "production": {
      "route": "yourdomain.com/*"
    }
  }
}

部署命令:

pnpm build && wrangler deploy --env production

第一次跑的时候会让你登录 Cloudflare 账号,浏览器里走一下授权流程就好。

域名怎么处理

如果你已经有一个域名,把它托管到 Cloudflare 就行。进 Cloudflare Dashboard,添加域名,然后去你的域名注册商那里把 DNS 服务器改成 Cloudflare 给的那两个 nameserver,等待生效,通常半小时以内。

域名托管到 Cloudflare 之后,SSL 证书是自动签发的,不需要额外配置。HTTPS 就这么有了。

如果还没有域名,注册一个 .com 大概每年 10 美元左右。这是这套方案里唯一需要花钱的地方。如果连域名钱也不想花,可以用 Cloudflare Pages 提供的 *.pages.dev 免费子域名,同样支持 HTTPS。

写作流程

配好之后,写文章就是在 src/content/blog/ 里新建一个 .md 文件,写 frontmatter,然后正文用 Markdown 写。

本地预览:

pnpm dev

写完之后推到 GitHub,如果配了 CI 就自动部署,没配的话手动跑一下 pnpm deploy 也行。

我目前用的是手动部署,还没有接 CI,每次改完本地确认没问题再推。博客更新频率不高,这样反而更简单。

踩过的坑

有一点值得提一下。Astro 配合 @astrojs/cloudflare 之后,部分 Node.js 内置模块在运行时是不可用的,因为 Workers 的 runtime 不是 Node.js,而是基于 V8 的 workerd。如果你在代码里用了 node:fsnode:path 这些模块,构建可以过,但运行时会报错。

这个问题的解法是在 wrangler.jsonc 里启用 nodejs_compat 兼容标志:

{
  "compatibility_flags": ["nodejs_compat"]
}

不过更推荐的方式是尽量避免在运行时依赖 Node.js 专有 API,把需要文件系统的逻辑移到构建阶段处理。这样生成出来的 Worker 代码更干净,也不依赖兼容层。

整体感受

跑起来之后,整个方案的维护成本很低。Cloudflare 的基础设施帮你处理了 CDN、SSL、DDoS 防护这些事情,博客本身没有数据库,没有服务器需要管,出问题的概率很小。

速度也不错。静态资源走 Cloudflare 的 CDN 节点,国内访问延迟基本在 50ms 以内。

唯一的限制是 Workers 的 CPU 时间:每次请求最多 10ms(免费套餐)。对于博客这种场景完全不是瓶颈,但如果你想在上面跑一些计算密集的东西,就得注意了。