Hexo 静态博客框架 NexT 主题配置教程

写在前面

Hexo 是一款基于 Node.js 的静态博客框架。它通过解析 Markdown 文章生成静态网页。只需要将 Hexo 生成的文件托管到平台上,即可完成博客的部署。

Hexo 的主题包非常丰富,NexT 主题是其中的佼佼者,本文将使用该主题搭建博客,首先介绍如何从零开始搭建一个本地的 Hexo 运行环境,然后讲解如何将你的网站发布到云端。

相关链接

有精力更深入探索的同学可以自行阅读 Hexo 和 NexT 的官方文档,以获得更全面的了解。

Hexo 仓库:github.com/hexojs/hexo
Hexo 文档:hexo.io
NexT 仓库:github.com/next-theme/hexo-theme-next
NexT 文档:theme-next.js.org

推荐使用 Visual Studio Code 和它自带的 Terminal 来帮助我们管理博客。以获得最佳开发体验。

Visual Studio Code:code.visualstudio.com

本地 Hexo 配置

从安装环境开始

我们需要在本地安装 Node.js,用于提供 JavaScript 运行环境,并提供 npm 包管理器用于安装 Hexo 框架、NexT 主题和相关插件。

为了直接从 GitHub 下载主题,或者把博客部署到服务器或 GitHub,我们还需要安装 Git。

Node.js:nodejs.org
Git:git-scm.com

初始化站点文件夹

0xfaner 的用户目录下有一个 WorkSpace 文件夹,他的很多仓库都放在这个文件夹下。现在我们将要在这个文件夹下创建一个名为 hexo-blog 的文件夹,作为博客项目的根目录。

我们首先安装 Hexo 的命令行界面(Command line interface),然后在自己指定的目录下初始化 Hexo,并进入站点文件夹中。

1
2
3
4
cd ~\WorkSpace
npm install hexo-cli -g
hexo init hexo-blog
cd hexo-blog

认识 Hexo 命令

现在我们已经得到了一个初始的 Hexo 博客。让我们先认识一下 Hexo 的一些命令,再对博客进行个性化配置。

  • hexo clean: 清除生成的静态文件和缓存;
  • hexo generate: 生成静态文件,可以简写为 hexo g
    • hexo generate -d: 生成静态文件后将其部署,相当于 hexo generate && hexo deploy,可以简写为 hexo g -d
  • hexo server: 启动网站服务,此时可以在浏览器中访问网站,可以简写为 hexo s
    • hexo server --port [port]: 指定服务端口,可以简写为 hexo s -p [port]
    • hexo server --open: 启动服务后立即在本机默认浏览器中打开网站,可以简写为 hexo s -o
  • hexo deploy: 用于部署静态文件到远端服务器或平台,可以简写为 hexo s -o
    • hexo deploy -g: 部署前生成静态文件,相当于 hexo generate && hexo deploy,可以简写为 hexo d -g

大多数时候我们只需要用到两个组合命令。

  • preview: hexo clean && hexo generate && hexo server --port 80 --open: 重新生成静态文件后在 80 端口启动网站服务并打开网页预览博客。
  • publish: hexo clean && hexo generate && hexo deploy: 重新生成静态文件后部署到远端服务器或平台。

读者们可以尝试在本地运行一下 preview 命令,浏览器将自动打开 localhost,你将看到你的初始博客的样子。在后续的配置中,你可以随时运行该命令来查看你的修改所起的效果。

使用技巧

平时我们要经常组合使用这些命令,但是在命令行中敲写命令还是稍慢,我们可以利用 Visual Studio Code 帮助运行脚本,在站点文件夹中找到 package.json 文件,添加两条脚本:

1
2
3
4
5
6
7
8
"scripts": {
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"server": "hexo server --port 80 --open",
"preview": "hexo clean && hexo generate && hexo server --port 80 --open",
"publish": "hexo clean && hexo generate && hexo deploy"
}

然后我们可以在 Visual Studio Code 的 Explorer 框中找到 NPM scripts 栏(找不到的话可以在 Explorer 右键菜单中勾选让它显示),点击相应条目的 run 按钮即可快捷运行相应脚本。

修改站点配置文件

站点的配置文件为站点文件夹下的 _config.yml 文件。该文件描述了站点的源信息:标题、副标题、语言、时区等。我们可以通过修改该文件来完成对站点的配置。

.yml 文件对应了标记语言 YAML,用来表示序列化数据。在后面我们还会看到对应了标记语言 Json.json 文件,功能和 YAML 接近,只是格式不同。

hexo server 运行中会检测博文的变动并进行动态更新,但是并不会检测配置文件的修改,你需要重新运行命令才能让更改生效。

安装 NexT 主题

在旧版 Hexo 中,应用主题的一个方式是从 GitHub 将主题仓库 Clone 到本地,放置在 Hexo 的 themes 文件夹下。这样一来整个主题对于用户来说就是透明的。我们可以随意修改主题文件夹内的任何文件来获得我们想要的效果,但这同时也带来了一些让人头疼的问题。

第一个问题是,NexT 主题更新非常频繁,如果我们想要让自己的主题保持最新,则需要不断与 GitHub 进行同步,我们不仅需要维护整个站点的仓库,还要单独维护主题仓库,定时从 GitHub 进行拉取。

第二个问题是,当我们对主题文件进行修改时,很容易让自己对 NexT 的修改与仓库的某处改动产生冲突,有时需要手动 Merge。

在新版 Hexo 中,有一个新方案解决了第一个问题,即使用包管理。我们可以使用包管理器(NPM)来将主题作为一个 JavaScript 包进行安装,运行以下命令即可。参考 Installation | NexT

1
npm install hexo-theme-next

从设计上来说,我们不应该直接修改 node_modules 文件夹中的内容。因此在这种情况下我们很难自由对主题进行自定义。一个有经验的开发者应当尝试直接给开源社区提 PR,这样不仅实现了自己的需求,更可以回馈开源社区。这种做法也直接消除了第二个问题:作为开发者,合并冲突根本不算什么,对吧?

使用技巧

我们可以全局安装 npm-check-updates 包来帮助我们检查 package.json 中的依赖是否是最新版本。

1
npm install npm-check-updates -g

检查更新时,我们只需要运行 ncu 命令即可,如果有待更新的包,则可以直接运行 ncu -u 命令来一键升级。

配置 NexT 主题

Hexo 的初始主题为 LandScape,我们对 _config.yml 进行修改,即可切换到 NexT 主题。

1
2
3
4
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: next

读者们可以运行 preview 命令来查看 NexT 主题的样子。

与 Hexo 一样,NexT 主题的配置也依靠 _config.yml 文件。但是注意站点和主题的配置文件不是同一个文件,站点配置文件位于博客文件夹根目录下,而主题配置文件位于主题文件夹下。如果主题是通过 Git 安装的,那么主题配置文件位于 themes\next 文件夹中。如果是通过包管理安装的,那么主题配置文件位于 node_modules\hexo-theme-next 文件夹中。

通常情况下我们可以直接修改主题配置文件来配置主题,但是并不推荐这么做。推荐使用 Alternate Theme Config(备用主题配置)来配置 NexT。具体地,我们将主题配置文件复制到博客根目录,命名为 _config.next.yml,然后对该文件进行修改即可。参考 Configuration | NexT

1
2
3
4
# Installed through npm
cp node_modules/hexo-theme-next/_config.yml _config.next.yml
# Installed through Git
cp themes/next/_config.yml _config.next.yml

配置插件

有些功能是 Hexo 默认关闭的,需要我们手动安装插件并启用,这里介绍一些常用的功能及其对应的插件。

数学公式

插件名:hexo-renderer-pandoc

当我们想要在博文中嵌入数学公式时,启用 \(\LaTeX\) 支持是一个明智的选择。不论是行内公式还是行间公式,都可以用一串简单的符号来表示。

Hexo 默认使用 hexo-renderer-marked 来进行渲染,但这个插件会导致 Markdown 标记和部分数学公式冲突,而 hexo-renderer-pandoc 则可以完美渲染。

若需要使用 hexo-renderer-pandoc,除了安装插件,还需要本地拥有 Pandoc 的环境。参考:Math Equations | NexT

1
2
npm uninstall hexo-renderer-marked
npm install hexo-renderer-pandoc

我们还需要在 _config.next.yml 文件中进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Math Formulas Render Support
# Warning: Please install / uninstall the relevant renderer according to the documentation.
# See: https://theme-next.js.org/docs/third-party-services/math-equations
# Server-side plugin: https://github.com/next-theme/hexo-filter-mathjax
math:
# Default (false) will load mathjax / katex script on demand.
# That is it only render those page which has `mathjax: true` in front-matter.
# If you set it to true, it will load mathjax / katex script EVERY PAGE.
every_page: true

mathjax:
enable: true
# Available values: none | ams | all
tags: all

katex:
enable: false
# See: https://github.com/KaTeX/KaTeX/tree/master/contrib/copy-tex
copy_tex: false

数据检索

插件名:hexo-generator-searchdb

专为 NexT 开发的数据检索插件,可以在侧边栏中看到一个检索按钮,点击即可弹出数据检索框,当你的博文内容较多时,启用搜索是个明智的选择。

1
npm install hexo-generator-searchdb

我们还需要在 _config.next.yml 文件中进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# ---------------------------------------------------------------
# Search Services
# See: https://theme-next.js.org/docs/third-party-services/search-services
# ---------------------------------------------------------------

# Local Search
# Dependencies: https://github.com/next-theme/hexo-generator-searchdb
local_search:
enable: true
# If auto, trigger search by changing input.
# If manual, trigger search by pressing enter key or search button.
trigger: auto
# Show top n results per article, show all results by setting to -1
top_n_per_article: -1
# Unescape html strings to the readable one.
unescape: true
# Preload the search data when the page loads.
preload: false

字数统计

插件名:hexo-word-counter

专为 NexT 开发的字数统计插件,可以在每一篇文章的标题下显示字数,并在博客页脚显示整个博客的总字数。

1
npm install hexo-word-counter

我们还需要在 _config.next.yml 文件中进行修改。

1
2
3
4
5
# Post wordcount display settings
# Dependencies: https://github.com/next-theme/hexo-word-counter
symbols_count_time:
separated_meta: true
item_text_total: true

远端部署

插件名:hexo-deployer-git

Hexo 官方提供的基于 Git 的部署插件,安装该插件后才可以使用 hexo deploy 命令。

1
npm install hexo-deployer-git

我们还需要在 _config.yml 文件中进行修改。

1
2
3
4
5
6
7
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
repo:
github: git@github.com:0xfaner/0xfaner.github.io.git
branch: master

如果是希望部署到服务器,那么我们必须使用该插件,但如果是希望部署到 GitHub,我们可以采用其他方案。

部署到 GitHub

GitHub 是世界上最大最先进的代码托管平台,当我们注册完账号,可以将自己的代码托管在 GitHub 中。同时 GitHub 提供了 GitHub Pages 的服务,它是一个静态站点托管服务,直接从 GitHub 上的存储库中获取 HTML、CSS 和 JavaScript 文件,并生成网站。

有两种方案进行博客的部署:

  • 第一种:将站点源文件保存在本地,利用 hexo-deployer-git 插件将博客部署到 GitHub Pages。

  • 第二种:将站点源文件保存在 GitHub,利用 GitHub Action,每次源文件仓库更新时自动部署到 GitHub Pages。

第一种方案较为常用,但第二种方案更为优秀。让我们细数第二种方案有哪些优点:

  1. 所有的文件都在 GitHub 有备份,数据更安全;
  2. 版本管理工具 Git 可以让站点源文件的变化清晰可见可溯源;
  3. 当我们配好博客设置并部署到 GitHub 后即可抛弃本地环境,添加博文可以直接在 GitHub 网站中完成,实现在线写作。

本文将介绍第二种方案。

配置本地 Git

首先配置本地的 Git 的用户名和邮箱。

1
2
git config --global user.name "0xfaner"
git config --global user.email "0xfaner@gmail.com"

然后生成密钥。

1
ssh-keygen -t rsa -C "0xfaner@gmail.com"

生成过程中会需要我们输入三次信息,分别是需要保存密钥的位置,密钥的密码和重复密钥的密码,我们无需理会,全部回车跳过即可。密钥的位置默认保存在 ~\.ssh\ 文件夹中,其中私钥是 id_rsa 文件,公钥是 id_rsa.pub 文件。

创建 GitHub 账户

我们需要在 GitHub 注册一个账号,并在本地安装 Git 来将本地生成的静态文件部署到 GitHub Pages。

创建 GitHub 仓库

我们先在 GitHub 中创建两个仓库:

  • 第一个名为 0xfaner.github.io :用作 GitHub Pages 的仓库。注意开头必须为自己 GitHub 账号的 username 而不是 nickname
  • 第二个名为 hexo-blog:站点源文件的仓库。当然这个仓库的名字你可以自由发挥。

添加 SSH key

创建完仓库后,我们要让本地的 Git 获得操作仓库的权限。复制公钥的内容,加入到 GitHub 账号的 SSH Key 中。

使用以下命令快捷复制公钥内容到剪贴板。访问网页 github.com/settings/ssh/new 即可快捷为 GitHub 账户添加 SSH 密钥,将公钥的内容粘贴到 Key 框中,Title 可以随意命名,点击 Add SSH key 即可完成 SSH 密钥的添加。

1
cat ~\.ssh\id_rsa.pub | clip

获取 Personal access token

为了让 GitHub Action 有权限向你的仓库 push 静态文件,我们需要创建一个 Personal access tokens(简称 Pat)。访问网页 github.com/settings/tokens/new 以进行创建。

其中 Note 可以随意填写,Expiration 可以设置为无限,但是为了安全起见,也可以设置为一个有限的期限。不过你要记得在它过期以前及时更新。权限部分只要勾上 repo 的权限即可。点击创建以后,你会获得一个以 ghp_ 开头的字符串,这就是你的 Pat,将它保存好。

设置 Actions secret

为了让你的 GitHub Action 能够获取到 Pat,同时又不把它泄露出去,你需要在你站点源文件仓库的设置页面中找到 Secrets 选项的 Actions 子选项,将你的 Pat 加入到里面。

填写时需要键入一个键值对,键可以随意起名,0xfaner 使用的是 HEXO_CI_TOKEN,值即为你的 Pat。在下面的 GitHub Action 配置文件中,我们会通过 ${{secrets.HEXO_CI_TOKEN}} 来获取到你的 Pat。

修改 GitHub Action 配置文件

我们需要在 Hexo 根目录下创建 .github\workflows 文件夹,该文件夹下的 .yml 将被视为 GitHub Action 的配置文件,文件名可以自定义,本文采用 deploy.yml

我们在 .github\workflows\deploy.yml 文件中写入如下内容。

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
name: Deploy
on:
push:
branches: [master]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16'
- name: Install Dependencies
run: |
sudo apt install pandoc
npm install
- name: Build Hexo Site
run: |
npm run build
- name: Deploy To GitHub Pages
working-directory: public
run: |
git init
git add -A
git -c user.name='0xfaner' -c user.email='0xfaner@gmail.com' commit -m 'site update'
git remote add origin https://${{secrets.HEXO_CI_TOKEN}}@github.com/0xfaner/0xfaner.github.io.git
git push origin master -f -q

其中包括四个步骤:

  • 准备环境:使用 Ubuntu 环境,加入 Git 和 Node.js 的支持;

  • Install Dependencies:安装 NPM 依赖,Pandoc 是数学公式插件的要求;

  • Build Hexo Site: 执行 NPM 脚本 build,生成静态文件;

  • Deploy To GitHub Pages: 用 Git 将静态文件部署到 GitHub Pages。

这个 GitHub Action 将在你向站点源文件仓库 Push 代码时触发,它会自动创建环境、安装依赖、生成静态文件并部署到 GitHub。

收尾

现在让我们将站点源代码项目 Push 到 GitHub 中去,GitHub Action 将会自动运行。

1
2
3
4
git add .
git commit -m "first commit"
git remote add origin git@github.com:0xfaner/hexo-blog.git
git push -u origin master

部署到远程服务器

从安装环境开始

如果我们希望将博客部署到远程服务器,那么我们就没有 GitHub Pages 和 GitHub Actions 可用了。

服务器中需要安装 Git 和 Nginx,分别用于接受静态文件,和建立网站服务,本文中服务器系统为 Debian。

配置本地 Hexo

我们需要安装对应的插件。可以参考前文的远程部署

配置本地 Git

我们需要在本地配好 Git 公钥私钥和用户名密码。可以参考前文的配置本地 Git

配置服务器 Git

首先使用包管理安装 Git,然后查看 Git 是否安装完成。

1
2
sudo apt install git -y 
git --version

出于安全考虑,我们新建一个名为 git 的用户,专门用于接受静态文件,然后切换到 git 用户。

1
2
3
useradd git
passwd git
su git

然后我们分别配置 Git 仓库的路径和静态文件的路径。Git 仓库目录在 /home/git/repos/blog.git ,静态文件部署在 /home/git/projects/blog

1
2
3
4
cd /home/git/
mkdir -p projects/blog
mkdir repos && cd repos
git init --bare blog.git

我们需要配置 Git,利用 post-receive 实现自动化部署。

1
2
cd blog.git/hooks
vim post-receive

输入内容如下(不了解文本编辑器 Vim 操作的用户需要自行了解一下)。

1
2
#!/bin/sh
git --work-tree=/home/git/projects/blog --git-dir=/home/git/repos/blog.git checkout -f

然后配置可执行权限。

1
2
3
chmod +x post-receive
exit
chown -R git:git /home/git/repos/blog.git

然后我们测试一下仓库是否成功配置,在本地运行命令尝试将远端仓库 Clone 下来。

1
git clone git@0xfaner.site:/home/git/repos/blog.git

如果能够把空仓库拉下来就说明配置完成。

然后我们建立 SSH 信任关系:

ssh-copy-id 命令为 Git Bash 自带。

1
2
ssh-copy-id -i ~/.ssh/id_rsa.pub git@0xfaner.site
ssh -T git@0xfaner.site

如果不需要密码而成功登陆了,那么说明配置完成,运行命令 logout 即可退出登录。

安全起见,修改 /etc/passwd 文件,让 git 用户默认使用 Git Shell,这样它就只能使用 git clonegit push 等命令。

1
2
- git:x:1000:1000::/home/git:/bin/bash
+ git:x:1000:1000::/home/git:/usr/bin/git-shell

配置 Nginx

首先使用包管理安装 Nginx,然后查看 Nginx 是否安装完成。

1
2
sudo apt install nginx -y
nginx -v

安装完成后,启动 Nginx。

1
sudo nginx

然后访问自己服务器的 IP 或域名来看看效果,如果无法访问,那么需要检查下服务器防火墙以及云服务器商的安全组策略。

修改 Nginx 的配置文件 nginx.conf,一般目录为 /etc/nginx/nginx.conf

1
sudo vim /etc/nginx/nginx.conf

如果目录位置不对,那么寻找一下 Nginx 的安装位置。

1
whereis nginx

根据显示的目录找一下。

将其中的 user 从默认的 nginx 改为 gitroot 以确保访问权限,防止出现 403 Forbidden 的无权限错误。

同时将根目录修改为静态文件所在的目录。

1
2
3
4
5
6
7
8
9
10
11
user git;
# ...
http {
# ...
server {
# ...
root /home/git/projects/blog;
# ...
}
# ...
}

开启 HTTPS 与 301 跳转

首先需要获取一份证书,可以使用 Let's Encrypt 的免费证书或在阿里云等服务商处代为申请。

因为是纯静态博客,所以也不需要用 Certbot 等工具进行一键 HTTPS 配置,直接在 Nginx 里面加载证书就行。

首先将证书传输到服务器中,包括 .pem.key 两个文件。然后将 nginx.conf 文件中的 HTTPS 部分取消注释,修改根目录,并配置证书路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
user git;
# ...
http {
# ...
server {
# ...
root /home/git/projects/blog;
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# ...
}
# ...
server {
# ...
root /home/git/projects/blog;
ssl_certificate "new_path";
ssl_certificate_key "new_path";
# ...
}
# ...
}

修改完成后,重启 Nginx 即可。

1
nginx -s reload

收尾

现在让我们在站点源代码执行命令,把静态文件发布到远程仓库吧。

1
npm run publish

后记

废了不少时间重建博客重写博文,希望以后可以不用再折腾这个博客了(哭