自主搭建博客 | Hexo + Butterfly 部署到 Cloudflare
为什么突然想搭博客
说起来有点好笑,起因是某天凌晨两点我在 Notion 里翻笔记,翻着翻着突然觉得——这些东西只有我自己能看到,好像少了点什么 (´•̥ ω •̥`)
其实这个念头挺早就有了。高中用过博客园,大学开始转 Notion,笔记是越记越多,但每次想分享点什么,都得截图、压缩、发群里,这套流程走完人都累了,还不如不发。后来刷到几个大佬的个人博客,那种”打开就是我的地盘”的感觉,说实话有点馋 ✧
想来想去,还是想要一个真正属于自己的地方。不是平台,不是账号,就是那种打开域名、”哦这是我的”的感觉。能自己改样式、自己写页脚、自己决定什么能显示什么不能——这种掌控感,Notion 给不了。
对比 Hexo 和 Hugo 纠结了挺久。Hugo 确实快,构建速度快得离谱,但中文资料少,遇到问题搜半天搜不到那种感觉真的很痛苦。最后选了 Hexo,社区活跃,中文教程多,新手友好,出问题基本都能搜到答案。
主题一眼就相中了 Butterfly——卡片式布局,首页那个排版看着就很舒服,配色自由度也高,改成粉色二次元风格完全没障碍 (σ≧▽≦)σ。部署选 Cloudflare Pages,免费 + CDN + HTTPS + 自动部署,穷学生最爱,简直是慈善。
环境准备
我的开发环境是 Windows 11 + WSL2(Ubuntu 22.04),Node.js 用 nvm 管理版本。
没装 nvm 的先跑这一条:
1 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash |
💡 为什么用 nvm?因为以后维护多个项目时 Node 版本可能不一样,nvm 切版本就一行命令,比直接装省心太多了。
Git 也记得配好,WSL2 和 Windows 混用很容易出换行符的问题:
1 | git config --global core.autocrlf input |
本地跑起来
有一件事要先说清楚:项目一定要建在 Linux 文件系统里,就是 ~/ 下面,别放 /mnt/d/ 那种挂载目录。
我最开始就犯了这个错误,hexo g 跑了将近三分钟,以为是电脑的问题,后来挪到 ~/projects/ 下面,同样的命令五秒跑完。WSL2 访问 Windows 文件系统有跨层 IO 损耗,慢是正常的,但在里面跑 Hexo 真的是折磨自己 (;д;)
1 | mkdir -p ~/projects && cd ~/projects |
hexo init 会把基础目录结构都建好,大概长这样:
1 | my-blog/ |
装 Butterfly 主题:
1 | git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly |
Butterfly 用 Pug 写模板、Stylus 写样式,这两个渲染器必须装,少一个页面直接白屏报错。
编辑根目录的 _config.yml,找到 theme 那行改掉:
1 | theme: butterfly |
跑起来预览一下:
1 | npx hexo clean && npx hexo s |
打开 http://localhost:4000,看到页面的那一刻真的有点小激动 φ(≧ω≦*)♪
⚠️ WSL2 用户注意:localhost 打不开的话,跑
hostname -I拿到 IP,用http://你的IP:4000访问。我第一次就卡这里,对着空白页发呆了十分钟 (ˉ▽ˉ;)
推到 Cloudflare Pages
仓库结构设计
我把主题和博客源码放在同一个 Git 仓库,结构是这样的:
1 | Blog/ # Git 仓库根目录 |
本地开发我在 blog/themes/butterfly 建了软链接指向外面的主题目录,改主题文件很方便,能实时热更新看效果。但——软链接绝对不能提交到 Git,这是血泪教训。
第一次部署,CF 构建日志满屏 ELOOP: too many levels of symbolic links,排查了将近一个小时,最后才发现是软链接的问题。CF 的构建容器里根本找不到软链接的目标路径,当然就报错了 (╯°□°)╯︵ ┻━┻
.gitignore 记得加上:
1 | blog/public/ |
Cloudflare Pages 配置
登录 Cloudflare Dashboard,进 Workers & Pages,新建 Pages 项目,连上 GitHub 仓库。
构建配置填这些:
| 配置项 | 值 |
|---|---|
| 框架预设 | None |
| 输出目录 | blog/public |
| 环境变量 | NODE_VERSION = 20 |
构建命令(核心是用 cp -R 替代软链接):
1 | rm -rf blog/themes/butterfly \ |
逐行解释:
- 清掉可能残留的旧主题文件
- 确保
themes/目录存在 - 把主题整个复制进来,替代软链接
npm ci严格按package-lock.json装依赖,锁版本,避免”本地好好的 CF 挂了”的玄学问题- 清缓存 + 生成静态文件
构建成功后会得到 xxx.pages.dev 的域名,有自己域名的话在 Custom Domains 里绑一下,CF 自动签 SSL 证书,全程不用手动操作。之后每次 git push 自动触发构建,一两分钟部署完 ヽ(✿゚▽゚)ノ
踩坑汇总 (>_<)
/mnt/下 IO 奇慢:项目必须放~/下,这条比什么都重要- 软链接报 ELOOP:用
cp -R代替,不要侥幸 - 时区错误导致文章日期偏移:在
package.json显式加moment-timezone依赖 - 构建偶发 OOM:文章多了以后可能内存不够,构建命令里加
NODE_OPTIONS=--max-old-space-size=512 - 首次构建卡住:CF 免费版有并发限制,等一会儿重试就好
主题折腾记录
配置文件的正确打开方式
在博客根目录建 _config.butterfly.yml,只写你改过的那些,主题默认值会自动继承,不需要复制整个默认配置文件。
好处很直接:以后主题更新了直接 git pull 拉新版,你的自定义配置完全不受影响。我有个朋友把整个默认配置复制进去了,主题更新加了新配置项,他的覆盖文件里没有,功能死活开不了,最后手动 diff 了半个小时 (..•˘_˘•..)
字体方案
1 | # _config.butterfly.yml |
霞鹜文楷是免费开源的中文字体,有点手写感,配上 Fira Code 的连字特性,代码块和正文都挺好看的。字体建议通过 CDN 引入或者自己托管,别只写字体名期望系统字体——用户机器上大概率没装 (>﹏<)
配色方案
这是我折腾最久的部分,大概改了三四版才满意。
1 | theme_color: |
暗色模式单独配了一套,主色换成深玫瑰 #be185d,保证和暗色背景的对比度能过 WCAG AA 标准(对比度 ≥ 4.5:1)。这个细节很多配色教程都不提,但对可访问性很重要,调色的时候顺手用 Colour Contrast Checker 验一下就好了。
彩色标签
默认标签样式比较单调,用自定义 CSS 做了 6 色循环:
1 | /* 注入到 custom.css 或 inject.bottom */ |
翻标签页的时候一堆彩色标签真的很好看,强烈安利 (ノ◕ヮ◕)ノ*:・゚✧
性能优化
1 | # 图片懒加载 |
图片我全部手动转成 WebP 再上传,体积能压到原来的 30%~50%。用 cwebp 批量转换:
1 | for f in *.png *.jpg; do cwebp "$f" -o "${f%.*}.webp"; done |
字数统计和 SEO
1 | # 字数统计 + 预计阅读时间 |
安全响应头通过仓库根目录的 _headers 文件配置(CF Pages 原生支持):
1 | /* |
最后说两句
博客目前部署在 blog.fovoen.moe,欢迎来玩 ♡
整个折腾下来,踩的坑其实不算太多,最坑的就是那个软链接问题,排查 + 修复将近两个小时。现在回头看都是小问题,但当时对着构建日志发呆真的很崩溃 (ノ_<。) 写这篇就是希望后来的人能少走一点弯路。
如果你也想搭,记住这几条核心原则:
- WSL2 项目放 Linux 文件系统,
~/projects/而不是/mnt/d/ - 主题配置只写差异项,用
_config.butterfly.yml覆盖默认值 - CF Pages 用
cp -R替代软链接,别抱侥幸心理 - 用
npm ci而不是npm install,锁版本保证构建稳定 - 图片转 WebP,体积和加载速度都会好看很多
希望能帮到同样在折腾博客的你 (๑•̀ㅂ•́)و✧~
参考链接:

