部署方案

此方案需要两个仓库:

  1. 源码仓库(私有):Hexo 配置文件以及写作等 原始内容 均在此操作进行,向此仓库 push 后通过 GitHub Actions 部署,并向页面仓库推送。
  2. 页面仓库(公开):通过 Hexo 生成的静态文件存储与此,GitHub Pages 检测到仓库更新会自动进行部署。

准备工作

需要 GitHub 账号一个,一台装有 GitNodejs 的电脑,脑子,手。

安装 hexo-cli (Hexo 主程序)

1
npm install hexo-cli -g

找到合适的目录作为博客根目录,打开 Git Bash 并运行命令:

(此过程会执行 git clone操作, 网络环境不良可能需要多次重试)

1
hexo init

当看到 “Start blogging with Hexo!” 时表示 Hexo 已经初始化完成。

启动 Hexo 本地服务端

1
hexo server

当看到 “Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.” 时表示 Hexo 本地服务端启动完成,其中 http://localhost:4000 为本地监听地址,访问该地址即可预览博客。

配置博客(WIP)

编辑 _config.yml 文件。下面提供一个模板(该内容可能过时,具体请参考 Hexo 官方文档)

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/

# Site
title: Hexo
subtitle: ''
description: ''
keywords:
author: John Doe
language: en
timezone: ''

# URL
## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project'
url: http://example.com
permalink: :year/:month/:day/:title/
permalink_defaults:
pretty_urls:
trailing_index: true # Set to false to remove trailing 'index.html' from permalinks
trailing_html: true # Set to false to remove trailing '.html' from permalinks

# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:

# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
external_link:
enable: true # Open external links in new tab
field: site # Apply to the whole site
exclude: ''
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false
prismjs:
enable: false
preprocess: true
line_number: true
tab_replace: ''

# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
path: ''
per_page: 10
order_by: -date

# Category & Tag
default_category: uncategorized
category_map:
tag_map:

# Metadata elements
## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
meta_generator: true

# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss
## updated_option supports 'mtime', 'date', 'empty'
updated_option: 'mtime'

# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page

# Include / Exclude file(s)
## include:/exclude: options only apply to the 'source/' folder
include:
exclude:
ignore:

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: landscape

# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: ''

美化(可选)

访问 https://hexo.io/themes 挑选喜爱的主题,作者一般会提供安装引导,不在此赘述。

安装方式一般如下:

托管站点

妥善保管源数据

目前 Hexo 程序仅安装在本机,一旦文章源码等丢失,恢复工作区的成本将会是巨大的。所以在此提出的方案是将文章源码托管到 GitHub 私有仓库。

  • 在 GitHub 上建立私有仓库
  • 在 Hexo 根目录执行(其中 $REPOSITORY_URL 替换为你实际的私有仓库 URL)
1
2
3
4
5
6
git init
git add .
git commit -m "init"
git branch -M master
git remote add origin $REPOSITORY_URL
git push -u origin master

托管博客页面

  • 在 GitHub 上建立公开仓库,一般命名为 $GITHUB_USERNAME.github.io,其中 $GITHUB_USERNAME 为你的 GitHub 用户名。(如果按照本条叙述,仓库符合要求的话,GitHub Pages 默认应该是开启的)
  • 本地生成部署用秘钥对(其中 $YOUR_EMAIL 替换为你的 Git 邮箱,$PAGES_DEPLOY_KEY 替换为密钥文件名)
1
ssh-keygen -t rsa -C "$YOUR_EMAIL" -f ~/.ssh/$PAGES_DEPLOY_KEY
  • 设置页面仓库 Deploy Key (Settings -> Deploy keys -> Add deploy key),将 ~/.ssh/$PAGES_DEPLOY_KEY.pub(公钥)文件内容粘贴 Key 文本框并勾选下方 Allow write access 选择框(开启部署秘钥仓库写权限)
  • 设置源码仓库 Repository secrets (Settings -> Secrets and variable -> Actions -> New repository secret)
    • Name 直接填写 DEPLOY_PRIVATE_KEY
    • Secret 填写 ~/.ssh/$PAGES_DEPLOY_KEY(私钥)文件内容
  • 编写源码仓库 GitHub Actions 自动化流水线脚本
    • 源码仓库中的 .github/workflows 目录中新建文件 CI.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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
name: CI

on:
push:

jobs:
hexo-deployment:
runs-on: ubuntu-latest

steps:
- name: Checkout source
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Restore file modification time
run: find source -name '*.md' | while read file; do touch -d "$(git log -1 --format="@%ct" "$file")" "$file"; done

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT}

- uses: actions/cache@v3
id: npm-cache # use this to check for `cache-hit` ==> if: steps.npm-cache.outputs.cache-hit != 'true'
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies & Generate static files
run: |
node -v
npm i -g hexo-cli
npm i
hexo clean
hexo g

- name: Upload assets to GitHub Action
uses: actions/upload-artifact@v3
with:
path: public

- name: Deploy to GitHub
uses: s0/[email protected]
env:
BRANCH: master
# CLEAR_GLOBS_FILE: '.clear-target-files'
FOLDER: public
MESSAGE: '[Blog#{sha}]{msg}'
# 这一行填写你页面仓库的 git 地址
REPO: [email protected]:someone/some-repo.git
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }}

注:GitHub Actions 针对公开仓库提供无限制的运行时间。GitHub Actions 针对私有仓库提供 2000 分钟/月运行时间(Pro 计划为 3000 分钟/月)只是写写博客免费计划绰绰有余。

后记

有关 HTTPS 问题。

如果使用 GitHub Pages 域名,即 xxx.github.io,则默认启用 HTTPS。

如果使用别名(即自己的 CNAME 解析)且带 CDN 加速服务需要注意,这里以 CloudFlare 为例,在面板中配置 CNAME 后,请暂时不要启用 CloudFlare 提供的代理服务,先回到 GitHub Pages 配置页面,等待 Enforce HTTPS 选择框亮起并勾选(如果开启了 CloudFlare 邮件通知,则会收到证书透明度邮件)后,再启用 CDN 代理。

虽然 GitHub Pages 中不开启强制 HTTPS 连接直接启用 CDN 在访问博客时同样提示为 HTTPS 安全连接,但事实上这个 HTTPS 形同虚设:

客户端(浏览器) <— HTTPS —> CDN <— HTTP —> 服务端(GitHub Pages)

而边缘证书成功申请后 HTTPS 才是真正有效的:

客户端(浏览器) <— HTTPS —> CDN <— HTTPS —> 服务端(GitHub Pages)

此问题的原始链接:https://gist.github.com/zbeekman/ac6eeb41ea7980f410959b13416d74c9

安装主题导致部署后的页面空白

通过 Git 安装的主题需要创建子模块(submodule)来嵌入源码仓库

如果已经安装主题,请移除 themes/$YOUR_THEME,其中 $YOUR_THEME 为你的主题目录名。按如下例子修改命令,重新安装主题(以 NexT 主题为例):

1
2
- git clone https://github.com/next-theme/hexo-theme-next themes/next
+ git submodule add https://github.com/next-theme/hexo-theme-next themes/next

首先应当注意到新的 .gitmodules 文件。 该配置文件保存了项目 URL 与已经拉取的本地目录之间的映射:

1
2
3
[submodule "themes/next"]
path = themes/next
url = [email protected]:next-theme/hexo-theme-next.git

如果有多个子模块,该文件中就会有多条记录。 要重点注意的是,该文件也像 .gitignore 文件一样受到(通过)版本控制。 它会和该项目的其他部分一同被拉取推送。 这就是克隆该项目的人知道去哪获得子模块的原因。

然后需要修改 .github/workflows/CI.tml 文件:

1
2
3
4
5
6
7
8
9
    steps:
- name: Checkout source
uses: actions/checkout@v3
with:
+ submodules: recursive
fetch-depth: 0

- name: Restore file modification time
run: find source -name '*.md' | while read file; do touch -d "$(git log -1 --format="@%ct" "$file")" "$file"; done

这么做是让 GitHub Actions 在运行 checkout 工作流时,将子模块一同拉取,保证主题也正常被拉取到工作坏境中。

一切完成后还需要将执行下述命令来将本地修改推送到远端仓库:

1
2
3
git add .
git commit -m "Fix theme submodule"
git push