Hexo 博客部署与重建记录
我已经记不得这是第几次重建博客了,虽然基于git仓库的备份,所有的md文件都还在,但是node_modules以及其他的环境配置会因为各种各样的原因损坏(换电脑,系统重装,迁移系统等),有必要重新梳理一下博客搭建的过程。
下面的内容主要是在Windows上和linux(WSL2)上的本地部署,以及在云服务器和Github Page的远程部署,并不涉及具体的Hexo主题以及配置细节。
生成与部署逻辑
Hexo是一个基于NodeJS的静态博客框架。首先梳理一下主要的工作逻辑:
- 在本地博客文件夹中,下载必要的Hexo组件并配置
- 在
source\_posts
目录中添加博客文件(markdown格式) - 生成并推送
- 执行
hexo generate
生成相应的静态网页,生成的静态网页及相关资源都会存放在public\
目录下 - 执行
hexo deploy
部署到远程仓库,实质上是将public\
目录下的所有内容打包复制到一个git本地仓库,然后提交到指定的远程仓库
- 执行
- 本地预览:执行
hexo server
启动本地预览,Hexo会在本地部署一个网站,通过http://localhost:4000访问。在本地启动期间,Hexo会持续监视博客文件变动并自动更新,无须重启服务器。但是对于配置文件的修改必须重启服务器才能生效。 - 清理本地缓存:执行
hexo clean
清理本地缓存(包括public\
和db.json文件),这可以有效避免一些错误。
日常写博客的流程:
- 启动本地预览:
hexo s
- 新建或修改博客文档
- 清理本地缓存:
hexo clean
- 生成并推送,完成博客的更新:
hexo g
,hexo d
由于Hexo生成的是静态网页,实际上我们只需要把public\
的所有内容复制到网站对应的目录下即可,然后配置Nginx确保文件夹可以被访问即可,通常这个复制过程使用git完成,但这并不是必须的。
本地搭建
准备工作
安装git,这没什么好说的。
安装nodejs(Latest LTS Version:
20.11.1),对于Windows很简单,对于Linux则略有不同,因为Ubuntu的apt提供的Nodejs版本太低,这里采用nvm给普通用户安装Nodejs,在普通用户家目录执行下面的命令安装nvm
1
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
这里给bash添加了一段配置,需要重新登录才能生效。
查看所有可供安装的node版本 1
nvm ls-remote
这里选择Latest LTS Version: 20.11.1安装 1
nvm install v20.11.1
查看本地已安装的node 1
nvm ls
使用指定版本的node 1
nvm use v20.11.1
安装pandoc(3.1.12.2),因为需要它来提供LaTeX渲染,在Windows上直接安装即可,Linux通过apt安装还是一样的问题——版本太低,安装过程如下:
首先通过pandoc的GitHub仓库下载pandoc-3.1.12.2-1-amd64.deb
文件并复制到家目录中,然后执行
1
sudo dpkg -i pandoc-3.1.12.2-1-amd64.deb
测试一下安装成功 1
pandoc -v
从零搭建
新建BlogBase/
文件夹,在其中本地安装hexo-cli
1 | npm i hexo-cli |
新建BlogBase/Blog
文件夹,在其中执行Hexo初始化(注意hexo必须在一个空文件夹里面进行初始化)
1
hexo init
由于hexo-cli不是全局安装的,存在找不到hexo命令的问题,对于Windows可以通过临时添加路径到PATH解决,在BlogBase目录下执行
1 $env:Path += ";$((Get-Item -Path .\node_modules\.bin -Force).FullName)"
对于Linux可以在Blog目录下添加hexo软链接 1
ln -s ~/blogbase/node_modules/.bin/hexo hexo
使用npm安装butterfly(butterfly主题不会放置在themes文件夹下)
1
npm install hexo-theme-butterfly
在_config.yml中切换主题,本地即可正常测试运行。
在基本功能测试完成之后,就可以安装插件并且进行相应配置,目前使用如下的插件:
- 本地搜索需要额外下载插件:hexo-generator-search
- 字数统计需要额外下载插件:hexo-wordcount
- 为了支持latex,首先需要root安装pandoc,然后卸载自带的hexo-renderer-marked,安装hexo-renderer-pandoc
- 部署的git插件默认也是没有的,需要安装hexo-deployer-git
- 一个似乎是支持置顶和隐藏的插件,卸载自带的hexo-generator-index,安装hexo-generator-index-custom
- 关于外链,安装hexo-filter-nofollow
- 关于sitemap,安装hexo-generator-sitemap
- 关于footer,安装hexo-butterfly-footer-beautify
如果npm下载的网络太慢,可以考虑换淘宝镜像源 1
npm config set registry https://registry.npmmirror.com
迁移搭建
如果已经有了Hexo博客的源代码仓库,那就更简单了:在BlogBase目录下安装hexo-cli之后,新建Blog文件夹并直接初始化Git仓库,然后拉取远程仓库的博客源代码仓库即可
1
2
3git init
git remote add origin <remote-url>
git pull origin main
然后自动下载依赖的插件(基于packages.json和packages-lock.json)
1
npm install
依赖顺利下载完成之后,就可以执行本地测试和进一步的部署了
1
hexo s
package.json
这里记录一下目前的package.json(2024年12月18日) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36{
"name": "hexo-site",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"server": "hexo server"
},
"hexo": {
"version": "7.3.0"
},
"dependencies": {
"hexo": "^7.0.0",
"hexo-abbrlink": "^2.2.1",
"hexo-butterfly-footer-beautify": "^1.0.6",
"hexo-deployer-git": "^4.0.0",
"hexo-filter-nofollow": "^2.0.2",
"hexo-generator-archive": "^2.0.0",
"hexo-generator-category": "^2.0.0",
"hexo-generator-feed": "^3.0.0",
"hexo-generator-index-custom": "^1.0.1",
"hexo-generator-search": "^2.4.3",
"hexo-generator-sitemap": "^3.0.1",
"hexo-generator-tag": "^2.0.0",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-pandoc": "^0.4.0",
"hexo-renderer-stylus": "^3.0.0",
"hexo-server": "^3.0.0",
"hexo-theme-butterfly": "^5.2.2",
"hexo-theme-landscape": "^1.0.0",
"hexo-wordcount": "^6.0.1",
"with": "https://registry.npmmirror.com/with/-/with-7.0.2.tgz"
}
}
补充:有的教程中npm
命令有--save
选项,代表将模块保存到
dependencies,但是目前的主流版本中已经不需要这个选项,这是默认行为。
更新记录
2024年5月10日更新:添加了
hexo-abbrlink
插件,为博客生成唯一的哈希值链接,不再依赖于路径。2024年9月2日更新:添加了
hexo-generator-feed
插件,为博客提供RSS支持。2024年12月18日更新:侵入式添加了随机封面图支持,在主题源文件中加了一个js脚本,在配置文件中也加入了相应配置,细节见下文。
远程部署
部署插件源码分析
远程部署如果基于Git实现,那么通常使用hexo-deployer-git插件,这个插件不是默认的插件,需要手动安装。(还有一些非Git的方式,Hexo也提供了名为hexo-deployer-xxx的插件)
hexo-deployer-git插件需要我们在_config.yml中加入如下形式的配置,这里提供了两个Git仓库的例子
1
2
3
4
5
6
7deploy:
- type: git
repo: git@fenglielie.top:blog.git
branch: main
- type: git
repo: git@github.com:<user>/<user>.github.io.git
branch: main
安装并配置好部署插件之后,hexo deploy
命令才会有具体的行为,实质等价于如下的命令:(分析depoly.js源码)
创建或清空
.deploy_git\
文件夹从
public\
文件夹复制所有内容到.deploy_git\
文件夹初始化 Git 仓库
1
git init
添加配置信息
1
2git config user.name "Your Name"
git config user.email "your.email@example.com"将所有文件添加到暂存区:
1
git add -A
提交
1
git commit -m "Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }}"
推送到远程仓库
1
git push -u <remote_repo_url> HEAD:<branch> --force
部署插件其实就做了这些事情,至于通过Git仓库具体部署到了什么地方,与本地的行为无关。
由于我们已经完全拆解了部署插件的行为,完全可以考虑直接自己写一个脚本来代替它,例如
1
2
3
4
5
6
7
8
9
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LOCAL_FOLDER_PATH="$SCRIPT_DIR/.deploy_git"
cd "$LOCAL_FOLDER_PATH"
# git remote add origin git@github.com:<user>/<user>.github.io.git
git push -u origin main
在Windows推送时,遇到了git换行符的问题,暂时把safecrlf从true改成warn,目前Windows中的.deploy_git的仓库级配置为
1
2 autocrlf = input
safecrlf = warn
云服务器配置
本地 hexo 推送到远程仓库 git@fenglielie.top:/home/git/blog.git,即通过 git 用户登陆云服务器的 ip。 这里需要先在云服务器中创建git用户,给 git 用户设置相应的 ssh 的密钥,并且在本地也设置相应的密钥,对于 git 用户通常还会禁用 shell 登陆。
具体的步骤如下:
- 第一步,部署到
/home/git/blog.git
文件夹,这是远程仓库的 git 仓库; - 第二步,调用
blog.git
里面的 hook(具体而言是hooks/post-receive
,也就是推送之后自动执行的动作),hook 的需要添加的内容如下,含义是将仓库的所有内容(也就是静态网站的所有内容,实际上就是public/
中的所有内容)在/home/open/blog
文件夹中展开1
git --work-tree=/home/open/blog --git-dir=/home/git/blog.git checkout -f
这里涉及到几个目录:
/home/git
以及它的子目录(git:git),存放当前云服务器上的所有远程仓库,包括/home/git/blog.git
博客仓库;/home/open
目录(root:root),存放了当前云服务器上所有的公开内容;/home/open/blog
目录(git:git),博客网站的主目录,里面存放了所有的网页文件。由于需要通过 git hook 进行读写操作,需要注意让git拥有权限。
注意,这里的
blog.git
仓库的大小可能随着推送次数增多而膨胀,可以过一段时间直接清空重置,但是要注意维护hooks/post-receive
。
可以考虑用另一个独立的git仓库备份所有博客及配置,单独调用git push
将
hexo 博客以及其它配置整体(不含node_modules/
)作为一个 git
仓库推送到远程仓库
git@fenglielie.top:blog_src.git
,这个远程仓库不需要设置
hook。
这里仅仅是把通过Hexo生成的静态网站所有内容放在了云服务器上的指定位置,为了让网站可以被外界通过网址成功访问,还需要考虑很多问题: 域名购买,服务器的公网ip与域名解析,SSL证书,腾讯云的防火墙+Linux系统防火墙,Nginx配置等。
Github Page配置
Github
Page是Github免费提供的,可以部署静态网站的服务,外界可以通过<user>.github.io
访问到网站。(当然也可以改成自定义域名,只需要改一下域名解析即可,这里暂不考虑)
Github
Page的实质和上面的云服务器配置是类似的,即本地将Git仓库推送到远程仓库,Github将远程仓库的内容放置在一个网站的根目录下,并且可以通过<user>.github.io
访问。
虽然原理类似,但是这个特殊仓库的配置,以及自动部署的过程还是值得注意的。
关于部署的内容,可以指定为仓库的某个分支,还可以进一步指定为某个文件夹。
有两种发布方式:
- (传统的)推送到特定分支时自动发布站点(使用默认的pages build and deployment工作流)
- (beta)编写 GitHub Actions 工作流来发布站点(使用自定义工作流)
前者直接把仓库指定分支的所有内容拷贝过去,用于部署网站;后者则基于Github Actions,即提供一个临时的虚拟机,可以在其中对仓库内容执行一些自定义的命令,然后将再部署网站。 目前选择前者即可。
补充:随机图支持
Hexo Butterfly 主题的封面图随机算法很差,即使我提供了很多的默认候选图,在生成html文件时仍然会固定(即部署时不再随机,仅生成时随机),而且这种随机算法很垃圾,每一个博客的封面图生成是相互独立的,容易出现连续几篇博客使用相同的候选图。
参考hexo
butterfly主题添加对随机图片api的支持中的做法:首先在/themes/butterfly/scripts/
目录下新建random_img.js
文件,脚本内容如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49/**
* Butterfly
* ramdom cover
*/
hexo.extend.filter.register('before_post_render', function (data) {
const { config } = this
if (config.post_asset_folder) {
const imgTestReg = /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/
const topImg = data.top_img
const cover = data.cover
if (topImg && topImg.indexOf('/') === -1 && imgTestReg.test(topImg)) data.top_img = data.path + topImg
if (cover && cover.indexOf('/') === -1) data.cover = data.path + cover
}
if (data.cover === false) {
data.randomcover = randomCover()
return data
}
data.cover = data.cover || randomCover()
return data
}, 0)
function randomCover() {
const theme = hexo.theme.config
let cover
let num
if (theme.cover && theme.cover.default_cover) {
if (!Array.isArray(theme.cover.default_cover)) {
cover = theme.cover.default_cover
} else {
num = Math.floor(Math.random() * theme.cover.default_cover.length)
cover = theme.cover.default_cover[num]
}
} else {
cover = theme.default_top_img || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
}
if (theme.cover.suffix) {
if (theme.cover.suffix == 1)
cover = cover + ("?" + Math.ceil(Math.random() * 10000))
else if (theme.cover.suffix == 2)
cover = cover + ("&" + Math.ceil(Math.random() * 10000))
}
return cover
}
然后修改配置文件,在cover
部分添加suffix: 1
选项。
最后一步是找一个不错的随机图API,推荐使用栗次元API。
这种侵入式的修改需要特别注意,因为在升级主题时很可能出现兼容性问题,也可能导致修改被覆盖。
补充:USTC HomePage
直接在Windows的文件浏览器路径栏输入ftp://home.ustc.edu.cn
,
输入登录名和密码,登录名是邮件帐号@
之前的部分,密码与邮件系统一样。
希望对外提供个人主页服务时,必须先创建子目录public_html/
,
这个目录里的所有文件均可以通过http://home.ustc.edu.cn/~YourID
来访问。在public_html/
中存放index.html
文件就可以提供默认首页,希望访问其它网页时,在URL中加上相对路径即可。