Hexo博客Workflow,2026版

2018年写过一篇Hexo博客Workflow,记录了怎么把这个博客在本地架起来,再把文章发布出去。

八年过去,博客还是Hexo,主题还是自己改过的NexT。写博客之前要回忆的命令,却还是有点多:源码在一个repo,主题在另一个repo,要同步submodule,要装依赖,最后还要记得部署和提交源码。这些事单独看都不复杂,但隔很久才写一篇的时候,每一步都得重新想一遍。

所以这次把workflow整理了一下。目标很简单:我只管写和编辑Markdown,剩下的事情交给GitHub Actions。

写作、发布

所有需要编辑的东西现在都在src-blog-yiyu-me这个私有仓库里,包括文章、主题、配置和自动发布流程。

最简单的写法,甚至不需要在本地安装Hexo:直接在GitHub网页上打开这个仓库,在source/_posts/下面新建一个Markdown文件。例如my-new-post.md:

1
2
3
4
5
6
7
---
title: 我的新文章
date: 2026-10-24 09:00:00
tags: 随笔
---

正文从这里开始。

提交到master,就会自动发布。修改旧文章也是一样:编辑对应的Markdown文件,再提交一次。

如果习惯在本地写,只需要clone这一个repo:

1
2
git clone https://github.com/erain/src-blog-yiyu-me.git
cd src-blog-yiyu-me

这是私有仓库,clone时需要使用有访问权限的GitHub账号。写好之后:

1
2
3
git add source/_posts/my-new-post.md
git commit -m "Add a new blog post"
git push origin master

这里用git add,是因为新建的文件也要加进版本控制。剩下的安装依赖、生成网站、发布,都不需要在本地做。

文章链接依然按照日期和文件名生成。比如上面的例子,对应的是/2026/10/24/my-new-post/。修改旧文章时保留文件名和date,原来的链接就不会变。暂时不想发布的文章放在source/_drafts/;当前配置不会生成这些草稿。文章日期本身不是定时发布开关。

如果想先预览

本地预览是可选的。需要的时候,安装Node.js 24,然后在仓库目录运行:

1
2
3
4
# 使用nvm管理Node.js的话,先读取仓库里的版本配置
nvm use
npm ci
npm run server

打开http://localhost:4000,就能看到本地博客。没有使用nvm的话,直接安装对应版本的Node.js即可。

也可以让Hexo帮忙创建文章:

1
npm run new -- "my-new-post"

发布前想检查完整构建,可以运行npm run build。它会执行hexo clean和hexo generate,把网站生成到public/。这个目录不需要提交,GitHub Actions会自己生成一份。

背后是怎么工作的

编辑的入口只有一个仓库,但背后仍然保留两个仓库的分工:

仓库 保存什么 谁来更新
src-blog-yiyu-me,私有 Markdown、主题配置、Hexo配置、Actions配置 我
erain.github.io,公开 生成好的HTML、CSS、JavaScript等静态文件 GitHub Actions

主题已升级到NexT 8,通过npm安装,具体版本由package.json和package-lock.json锁定。自己的主题设置放在源码仓库的_config.next.yml里面,在Pisces双栏布局上做了适合中文长文的排版,首页用摘要展示文章。站点的样式在source/_data/styles.styl,首页模板在layout/index.njk。要改配置,就和改文章一样,在这个仓库修改、提交。原来单独的主题仓库和submodule都不再是日常流程的一部分。

网站继续由原来的GitHub Pages托管,域名还是blog.yiyu.me。这次主要是把手工操作自动化,没有换博客引擎,也没有换托管方式。

整个流程可以画成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
编辑Markdown、提交到源码仓库的master
|
v
GitHub Actions:build
Node.js 24 + npm ci
Hexo + NexT -> public/
|
v
上传构建产物blog-public
|
v
GitHub Actions:deploy
下载同一份产物
同步到erain.github.io的master
|
v
GitHub Pages构建与部署
|
v
https://blog.yiyu.me

流程定义在源码仓库的.github/workflows/blog.yml里,分成build和deploy两个job。

build先取出源码,根据.nvmrc选择Node.js版本,再用npm ci按照package-lock.json安装依赖。这样不用依赖我电脑上碰巧装了什么。接下来执行完整构建,检查首页存在、CNAME里的域名正确,再把public/上传成一个名为blog-public的artifact,也就是这次构建的产物。

deploy必须等build成功后才能运行。它下载刚才生成的那份产物,把文件同步到发布仓库,提交并推送。同步时会删除已经不再生成的旧文件,保留发布仓库的Git记录;如果网站内容没有变化,就不产生新的提交。

最后,发布仓库的更新会触发GitHub Pages自己的构建和部署。源码仓库的Action成功,表示网站文件已经推送过去;还要等Pages部署成功,线上才算更新完成。

source/CNAME会随构建一起进入网站,继续使用原来的域名。发布时还会加上.nojekyll,让Pages直接提供Hexo已经生成好的静态文件。

两个仓库之间的钥匙

源码仓库的Action需要写入另一个仓库,因此单独配了一把SSH deploy key。公钥放在erain.github.io的Deploy keys里并允许写入,私钥放在源码仓库的Actions secret中,名字是BLOG_DEPLOY_KEY。

这把钥匙只对应发布仓库,不需要把我日常使用的个人SSH私钥交给Action。它是一次性配置,平时写文章不用碰。GitHub官方的deploy key文档解释了这种仓库级授权方式。

私有的是源码仓库,生成出来的网站仍然是公开的。写进正式文章的内容会发布到网上,这一点和以前一样。

怎么知道发布成功了

提交之后,先去源码仓库的Actions页面,看Build and publish blog这次运行是否成功。正常情况下,build和deploy都应该是绿色。

然后去erain.github.io的Actions页面,确认对应的pages-build-deployment也成功,最后打开文章的正式链接,检查标题、日期、正文、代码块,以及首页和归档里的入口。

如果build失败,先看构建日志,后面的发布不会执行,线上仍然保留之前的版本。如果deploy失败,检查发布日志和deploy key配置。如果两个job都成功、网页却没有更新,就继续看发布仓库的Pages任务,而不是只盯着源码仓库的绿色勾。

修正问题后再次提交,就会重新跑整个流程。也可以在源码仓库Actions页面选中这个workflow,用Run workflow手动重新发布master。Pull Request也会检查构建,但不会部署;合并到master后才正式发布。

八年前记下了怎么手动部署,八年后终于把部署这件事交给了机器。希望下次打开这个repo,是因为有东西想写。