别再把个人博客搭建想复杂了:从买域名到手机发文的完整指南
搭个人博客看起来像一件很简单的事:选个主题,写篇文章,再把网页放到网上。
真正做起来才会发现,问题不是“怎样生成一个首页”,而是怎样让写作、备份、构建、部署、域名和搜索引擎长期配合。我的博客也踩过不少坑:CMS 保存后没有触发 Actions、公式生成失败、主题样式在手机和电脑上同时错位、DNS 改完却忘了核对邮件记录。
回头看,这些问题大多来自同一个原因:一开始只看到了网页,没有先想清楚整个发布系统。
这篇文章从零整理一条完整路线。最终效果是:
- 文章使用 Markdown 保存;
- 源码和历史版本在 GitHub;
- GitHub Actions 自动构建并阻止错误上线;
- Cloudflare Pages 提供 HTTPS 和全球访问;
- 自定义域名作为唯一正式地址;
- Pages CMS 让电脑和手机都能在线写作。
本文使用 Node.js 22、Hexo 8.1.2 和 Keep 4.3.0 说明。软件版本会继续变化,安装时应同时查看文末官方文档。
先决定:为什么选择静态博客
个人博客常见方案大致分为两类。
| 方案 | 优点 | 代价 |
|---|---|---|
| WordPress 等动态 CMS | 后台完整、插件多、多人协作方便 | 需要数据库、服务器维护和安全更新 |
| Hexo 等静态生成器 | 快、便宜、文件可备份、攻击面小 | 评论、搜索和在线编辑需要额外方案 |
如果目标是个人写作、技术文章和长期归档,我更喜欢静态博客。文章就是 Markdown 文件,即使未来不用 Hexo,也能迁移到其他系统。
Hexo 的职责非常单纯:
1 | Markdown + 主题 + 配置 |
Cloudflare Pages 负责托管生成结果,GitHub 保存源码和版本历史。各部分可以替换,不会把内容锁死在某个平台。
第一步:准备环境
需要准备:
- Node.js;
- Git;
- GitHub 账号;
- 一个代码编辑器;
- 可选的个人域名。
安装后先检查:
1 | node --version |
然后安装 Hexo 命令行:
1 | npm install --global hexo-cli |
如果 PowerShell 提示无法运行 npm.ps1,可以暂时使用 npm.cmd;不要为了一个命令就随意关闭整台电脑的脚本安全策略。
第二步:创建 Hexo 项目
初始化一个新项目:
1 | hexo init my-blog |
Hexo 会生成几个关键位置:
1 | my-blog/ |
先不要急着改主题。执行:
1 | hexo server |
浏览器打开 http://localhost:4000/。默认博客能够显示,说明 Node、依赖和 Hexo 本身没有问题。先建立这个基线,后面出现故障才知道是主题还是环境。
第三步:安装 Keep 主题
本站使用 Keep。把主题作为 npm 依赖安装,比手动复制一份主题目录更容易升级:
1 | npm install hexo-theme-keep |
在 _config.yml 中设置:
1 | theme: keep |
再把主题默认配置复制到项目根目录:
1 | Copy-Item node_modules/hexo-theme-keep/_config.yml _config.keep.yml |
网站基础信息可以这样写:
1 | # _config.yml |
主题信息放在 _config.keep.yml:
1 | base_info: |
主题升级后,尽量把自己的修改保留在根目录配置和 source/ 中,不要直接改 node_modules。否则重新执行 npm install 后,修改可能全部消失。
第四步:写第一篇文章
创建文章:
1 | hexo new post "hello-blog" |
文件会出现在 source/_posts/。一篇比较完整的文章头部可以写成:
1 |
|
description 不只是给搜索引擎看的,它还迫使作者用一句话说明文章到底解决什么问题。不要让所有文章都复用网站简介。
分类通常只保留一个主要方向,标签可以有多个。这样既不会生成过多空洞分类,也方便以后整理专题。
如果启用了菜单中的分类、标签和关于页面,还要创建对应页面:
1 | hexo new page categories |
然后在 categories/index.md 和 tags/index.md 的 front matter 中分别增加:
1 | type: categories |
以及:
1 | type: tags |
只配置菜单却没有页面,是 Tags 和 Categories 打开后一片空白的常见原因。
第五步:把构建固定成命令
在 package.json 中增加:
1 | { |
日常本地检查:
1 | npm run clean |
对应的 Hexo 三件套是:
1 | hexo clean |
clean 不能总省略。主题、路由或生成器发生变化后,旧的 public/ 和数据库可能留下已经不存在的页面。
第六步:理解 source 和 public
Hexo 项目里最容易混淆的两类文件是:
source/:你真正维护的文章和静态资源;public/:Hexo 每次构建生成的网站。
不要直接修改 public/。下一次构建会覆盖它,而且源码仓库中找不到修改依据。
本站进一步使用两个 Git 分支:
| 分支 | 保存内容 |
|---|---|
source |
Markdown、配置、主题依赖、脚本 |
main |
public/ 中生成后的静态网站 |
第一次搭建也可以只用一个源码分支,让 Cloudflare Pages 执行 npm run build。等博客稳定后,再升级到双分支和发布检查。两种架构都能工作,关键是不要把它们混在一起。
更详细的两种部署方式,可以参考本站的 Hexo 8 + Keep 4 部署记录。
第七步:把源码交给 GitHub
在 GitHub 创建空仓库后,本地执行:
1 | git init |
提交前检查 .gitignore,至少不要提交:
1 | node_modules/ |
必须提交 package-lock.json。GitHub Actions 和 Cloudflare 才能通过 npm ci 安装与本地一致的依赖版本。
第八步:先完成一次手动部署
安装 Hexo Git 部署器:
1 | npm install hexo-deployer-git |
在 _config.yml 中设置:
1 | deploy: |
然后执行:
1 | npm run release |
部署器会把 public/ 推到 main。此时 GitHub 中应同时存在源码分支和生成分支。
使用私有仓库或自动化令牌时,不要把令牌直接写进 _config.yml。凭据应放在系统凭据管理器或 GitHub Secrets 中。
第九步:让 GitHub Actions 自动发布
在 .github/workflows/deploy-hexo.yml 创建工作流:
1 | name: Build and deploy Hexo |
这个工作流的意义不只是省去一次命令。以后还可以在 Build 阶段加入断链、公式、SEO 和图片检查。检查失败时不更新 main,正式网站继续保留上一个正常版本。
GitHub 官方也建议 Node 项目在 Actions 中固定 Node 版本并使用 npm ci,避免构建环境随运行器变化。
第十步:接入 Cloudflare Pages
进入 Cloudflare:
1 | Workers & Pages |
选择 GitHub 仓库。
如果 Cloudflare 连接的是 Hexo 源码分支:
1 | Production branch: source |
如果连接的是已经生成静态网站的 main:
1 | Production branch: main |
本站使用第二种方式:GitHub Actions 先构建检查,Cloudflare 只发布通过检查的静态结果。
部署完成后会得到:
1 | https://PROJECT.pages.dev/ |
先确认这个地址正常,再处理自定义域名。不要在构建还失败时同时折腾 DNS,否则很难区分问题发生在哪一层。
第十一步:绑定域名和 DNS
在 Pages 项目中进入:
1 | Custom domains |
输入 example.com。根域名需要位于同一个 Cloudflare 账户并使用 Cloudflare 名称服务器;Cloudflare 会协助创建记录和签发证书。
子域名通常使用:
1 | 类型: CNAME |
不要只在 DNS 页面创建记录,却不在 Pages 项目中添加 Custom domain。Pages 还需要知道应为哪个域名提供站点和证书。
如果域名同时用于邮箱,网站记录和邮件记录要分开处理:
- 网站通常使用 CNAME;
- 邮件接收依赖 MX;
- SPF、DKIM、DMARC 通常使用 TXT;
- 邮件相关记录不要开启 Cloudflare 代理。
第十二步:上线前补齐 SEO
至少检查:
_config.yml中的url是正式域名;- 每页有唯一
<title>和 description; - canonical 指向正式域名;
- 文章只有一个主标题;
- 图片有准确的 alt;
- 分类、标签和归档页不为空;
- 存在
robots.txt和sitemap.xml; - 404 页面能正常返回;
pages.dev不与正式域名重复收录。
安装 sitemap 和 RSS:
1 | npm install hexo-generator-sitemap hexo-generator-feed |
source/robots.txt 可以先写:
1 | User-agent: * |
上线后把 sitemap 提交到 Google Search Console 和 Bing Webmaster Tools。SEO 的基础不是关键词堆砌,而是让每个地址稳定、内容明确、内部链接可被发现。
第十三步:接入 Pages CMS
博客已经稳定发布后,再解决“怎样方便写文章”。
Pages CMS 会读取仓库根目录的 .pages.yml,把 Markdown 字段映射成在线表单。一个精简配置如下:
1 | media: |
media.input 是图片在仓库中的保存位置,media.output 是写进文章的公开 URL。两者混淆后,CMS 看似上传成功,线上却会出现断图。
Pages CMS 还可以添加按钮触发 workflow_dispatch。本站的实际配置、图片上传和 Actions 排查过程写在 Pages CMS + Hexo 8 实战 中。
第十四步:固定日常发布流程
以后每次写文章只需要:
1 | Pages CMS 或本地编辑 Markdown |
本地发布时:
1 | git pull |
CMS 发布时则只需填写标题、摘要、分类、标签和正文。它不是另一套数据库,最终保存的仍然是同一批 Markdown 文件。
最容易遇到的几个问题
本地正常,线上样式错乱
先比较本地 public/、GitHub main 和正式域名,不要马上加 CSS 补丁。确认主题源码有没有被当作文本输出、生成分支是否完整、浏览器是否仍在使用旧缓存。
本站曾经出现 Logo 被拉长、Stylus 源码进入 HTML 的情况,完整排查见一次 Hexo 主题样式事故复盘。
CMS 保存了,Actions 没有执行
依次检查:
- CMS 保存到哪个分支;
- workflow 的
on.push.branches是否包含该分支; - workflow 文件是否已经存在于对应分支;
- GitHub Actions 是否启用;
- Pages CMS GitHub App 是否获得仓库权限。
Tags 和 Categories 没内容
确认文章 front matter 真的包含 tags 和 categories,并且已创建带正确 type 的聚合页面。标签大小写也应统一。
公式显示为原始文本
Markdown 渲染器、KaTeX 插件和主题样式必须配套。升级 Hexo 后应重新构建所有含公式文章,并检查生成 HTML 中有没有未渲染的公式分隔符或 KaTeX 错误。
GitHub 已更新,域名仍是旧内容
先看 Actions 是否成功,再看 main 是否出现新 HTML,然后查看 Cloudflare 最新部署是否对应同一提交。只有这些都正确,才进入浏览器和 CDN 缓存排查。
上线检查清单
第一次宣布博客上线前,至少完成:
- 首页、文章页、分类和标签页都能打开;
- 手机和电脑没有明显布局错位;
- 新文章可以从写作端一路自动发布;
- GitHub 保存完整源码,而不只有
public/; - 域名、HTTPS、canonical 和 sitemap 使用同一个正式地址;
- 404、robots、RSS 和隐私页面存在;
- GitHub 开启双因素认证;
- 没有把令牌、邮箱密码或 API 密钥提交进仓库;
- 知道怎样回退到上一个正常提交。
最后:真正需要维护的是写作系统
一个个人博客不需要在第一天拥有评论、广告、统计、邮件订阅和几十个插件。先让下面四件事可靠:
- 文章不会丢;
- 发布可以重复;
- 错误能够阻止上线;
- 更换平台时内容仍能迁移。
域名是门牌,主题是装修,Cloudflare 是房屋托管;Markdown 和 Git 历史才是自己真正拥有的东西。
博客搭好以后,最理想的状态不是每天研究部署,而是打开页面就能写。剩下的复杂流程安静地待在后面,只有出错时才提醒你。