Hugo Blog托管到GitHub Pages

 

一、使能并配置 Github Pages

1、首先确保已经配置好了SSH Key,能正常执行git的各种操作;

在github上创建一个名为 YourGithubID.github.io 的仓,毕竟是blog使用的,没有特别的保密需求的话,用public仓即可;

如果用private仓,则需要升级成pro账户(每月4刀,勉强可以接受)才能使能 github pages 功能,github也是要恰饭的嘛,可以理解;

1-0

 

2、仓创建完毕后,打开repo的settings界面(不是账户的settings),找到“Pages”选项:

1-1

github pages 默认的build and deployment 的source是“deploy from a branch”;这个适用于直接上传hugo生成的public目录到个人仓的情况,比较麻烦,不够自动化,确实可以这样做,但不够自动和智能。

推荐使用从Action 构建,请选择“deploy from a branch” 菜单中的 “Github Actions”选项,这个选项是选择直接生效的,不需要点击任何确认;

1-2

 

3、选择Github Action后,可以看到选项下面内容刷新,有两个链接,此时点选第一个“browse all workflows”;

1-3

然后跳转到如下界面,请在搜索框中输入Hugo,然后敲回车搜索之;

1-4

通常只有如下一个搜索结果:

1-5

 

4、点击“Configure”按钮,打开配置界面,可以看到如下的代码编辑界面,此时啥也不需要改动,直接点击“Commit changes…”即可;

1-6

 

5、将创建好的仓git clone下来到本地备用;

1
2
cd ~
git clone rightsubtree@github.com:rightsubtree/rightsubtree.github.io.git

 

二、搭建Hugo本地网站

 

1、参考 https://gohugo.io/installation/ 在本地安装好hugo必备的可执行程序;

mac上比较方便,使用 brew install hugo 命令即可完成;

windows上可以从 https://github.com/gohugoio/hugo/releases 下载预编译好的包,通常只有一个hugo.exe文件,配置好环境变量就能直接在命令行使用了;

由于必然要用到git 命令,所以也请提前安装配置好git;

 

2、创建本地网站

下面命令创建一个名为“blog”的本地网站,hugo命令会自动创建目录,名称也无所谓,我们只是为了得到hugo网站的所有文件,很快就不在这个blog目录工作了;

1
2
3
cd ~
hugo new site blog
cd blog

此时可以看到如下目录:

2-1

将来的各种markdown文件一般存放在 content/posts 目录中;

hugo.toml 是hugo的配置文件;

static 目录主要用来存在各种图片等;【经过实地测试,如果md文档中包含图片,则必须放到static目录中,并使用绝对路径引用之。其他位置,例如content/posts等目录会导致引用失败,主要原因是hugo在生成网页时,会给每一个md创建一个独立的目录,从而导致我们设置的相对路径差了一个层次】

themes 目录顾名思义是存放各种主题的,此时它还是一个空目录,hugo不自带任何默认主题,需要我们手动下载并指定好;

 

3、将创建好的目录全部复制到github pages目录:

cp -fr ~/blog/* ~/rightsubtree.github.io

之所以这样做,是未来我们最终是要在github pages 目录执行所有操作的,提前将hugo的文件放到这里,方便管理;

 

4、接下来是下载和配置主题:

Hugo官方适合blog的主题都在这里:https://themes.gohugo.io/tags/blog/

打开详情页后,点击“Download”按钮,即可跳转到其github主页:

我当前使用的是这个FixIt主题:

2-3

然后使用如下命令将其下载:

1
2
cd ~/rightsubtree.github.io
git submodule add https://github.com/hugo-fixit/FixIt.git themes/FixIt

用submodule add是hugo官网推荐的方式,好处是可以将每个主题作为一个独立的git仓,后续方便随时通过git pull升级,但如果想手动修改一下某个主题的内容(例如favicon)就略有不便,本地的修改无法push到github(因为独立的git仓的push目标是主题作者的仓);

另一种方式是,直接clone下来,然后删除主题的.git目录,将主题作为github pages仓的普通文件递交到github pages仓,就能方便后续手动修改主题内的文件了;【另外,FixIt主题官方推荐的是直接下载正式release版本,而不是通过git clone获得主线版本】

1
2
3
cd ~/rightsubtree.github.io
git clone https://github.com/hugo-fixit/FixIt.git themes/FixIt
rm -fr themes/FixIt/.git

然后,编辑 hugo.toml 配置文件,在最后添加一行 theme = "FixIt" (引号后面的内容必须和下载主题时指定的themes目录下的子目录名相同);

 

5、配置了主题后,此时可以执行 hugo server 命令,使用hugo的本地server来查看blog的网页效果,命令执行完毕后,会显示一个localhost地址(默认端口是1313),点击即可打开本地网页;

2-4

 

效果如下,当前还没有任何实际网页,这里仅仅能看到空白的home页;

2-5

此时网站本地根目录内会新生成一个public目录,所有build出来的网页都在这个目录里面;

 

6、接下来,添加一个md文档:

hugo new content content/posts/hello-world.md

打开后,可见其只包含一些title信息:

【需要说明的是,不同的主题提供的md文档模板可能是不一样的,以你选定的主题为准】

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
---
title: Hello World
subtitle:
date: '2024-10-07T15:24:34+08:00'
#这个slug是一个临时url,但我觉得FixIt主题做得有些多余了,如果删除掉,则url就是md文件名
slug: e2aee69
draft: true
author:
  name:
  link:
  email:
  avatar:
description:
keywords:

#这里省略很多行……

---

注意,刚生成的文档都有“draft : true” 的配置,默认情况下,draft文档是不会被hugo server命令构建的,如果需要查看效果,可以使用命令 hugo server --buildDrafts 或者 hugo server -D 来构建并查看之;

当然,正式的文档里需要将其draft值改为false;

上面的title等描述信息称为Front Matter,是hugo执行build时必须的,所以,如果一个文档不是用hugo new content命令生成的,请记得手动将上述固定格式添加到md文档开头,否则hugo在build时会忽略文档;

Front Matter 支持使用YAML(以---为起止标志,Key和Value之间用冒号)、TOML(以+++为起止标志,Key和Value之间用等号)、JSON三种写法。请确保语法正确,混用的话(例如用---做起止标志,但KV之间用等号),会导致Hugo生成网页失败;

 

hello-world页面的效果如下(这里已经删除了slug一行):

2-6

 

7、关于md文档的内容,需要特别注意的一点是图片的引用。经过实测发现,hugo的md文档,只能将图片放到hugo跟目录的static 目录中,然后用绝对路径来引用它;

例如,存在文件 ~/rightsubtree.github.io/static/images/hello_world/flow-chart.png

则md中需要这样引用:

![flow-chart](/images/hello_world/flow-chart.png)

也就是说,将static当作所有静态资源的根目录,直接用绝对路径引用;

这个逻辑对于typora这样的markdown工具不太友好,预览图片不是很方便,只能在写md时先用本地相对路径,然后放到posts目录时再替换成绝对路径,然后用 hugo server 命令查看效果;

另外,hugo只支持markdown格式的图片引用,即 ![text](path) 这样格式的,不支持 <img> 格式的; 更准确地说,hugo是不支持在md里面插入任何html的标签,所以在typora里面用 <font color="red">这是红字</font> 来强调的方法就不适用了;

 

8、hugo.toml 里比较重要的配置:

 

baseURL = 'https://example.org/'

baseURL 用于配置网页的根url,如果使用github的默认域名,则需要配置为 baseURL = 'https://YourGithubID.github.io/' ,如果使用自定义域名,则对应配置;注意最后必须要有一个正斜杠!

在本地调试阶段(使用hugo server命令打开localhost网页时),是否配置baseURL不影响啥;

但是如果需要将blog文档发布到网络,则这一项必须是正确的值,否则网页之间的链接关系可能错误!

 

title = 'My New Hugo Site'

请根据实际需要改成你自己的网站的名字;

 

作为技术博客,我们希望用tags、series、categories的方式来自动组织内容,实现方法是:

第一步,先在 hugo.toml 里面添加如下内容:

1
2
3
4
[taxonomies]
  tag = "tags"
  series = "series"
  category = "categories"

  第二步,在具体的md文档的title部分(即上述md开头两个+++之间的部分),添加如下内容:

1
2
3
tags = ["frameworks", "binder"]
categories = ["Android"]
series = "frameworks"

即一篇文档可以有多个tags,归属多个categories,但只能属于一个series;

配置后,重新用hugo server 命令执行构建后,就可以看到网页已经自动按照标签、分类、系列整理文档的效果;

需要注意的是,不同的hugo主题对于标签、分类、系列的支持程度和展示效果是不一样的;

 

关于文章模板,Hugo自带的文章模板位于archetypes/default.md ,但如果使用了FixIt主题,则FixIt会使用自己的模板,其模板位于themes/FixIt/archetypes/posts.md 我自己将这个模板简单修改了一下,使用起来更顺手一些:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
---
title: {{ replace .TranslationBaseName "-" " " | title }}
subtitle: 
date: {{ .Date }}
draft: false

tags:
  - 标签1
  - 标签2

categories:
  - 分类1
  - 分类2

summary: ""

featuredImage: ""
featuredImagePreview: ""
---
正文

 

下面是我本地配置的hugo.toml 文件,仅供大家参考(多数内容是从FixIt主题里面的hugo.toml文件里摘出来的):

  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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
baseURL = 'https://rightsubtree.com/'
title = 'rightsubtree'
theme = "FixIt"
languageCode = "zh-CN"
defaultContentLanguage = 'zh-cn'
hasCJKLanguage = true

# default amount of posts in each pages
pagination.pagerSize = 6

[menu]
  [[menu.main]]
    identifier = "archives"
    name = "Archives"
    url = "/archives/"
    # title will be shown when you hover on this menu link
    title = ""
    weight = 1
    [menu.main.params]
      icon = "fa-solid fa-archive"
  [[menu.main]]
    identifier = "categories"
    name = "Categories"
    url = "/categories/"
    title = ""
    weight = 2
    [menu.main.params]
      icon = "fa-solid fa-folder-tree"
  [[menu.main]]
    identifier = "tags"
    name = "Tags"
    url = "/tags/"
    title = ""
    weight = 3
    [menu.main.params]
      icon = "fa-solid fa-tags"

[outputFormats]
  # FixIt 0.3.0 | NEW Options to make output /archives/index.html file
  [outputFormats.archives]
    path = "archives"
    baseName = "index"
    mediaType = "text/html"
    isPlainText = false
    isHTML = true
    permalinkable = true
    notAlternative = true
  # FixIt 0.3.0 | NEW Options to make output /offline/index.html file
  [outputFormats.offline]
    path = "offline"
    baseName = "index"
    mediaType = "text/html"
    isPlainText = false
    isHTML = true
    permalinkable = true
    notAlternative = true
  # FixIt 0.3.0 | NEW Options to make output readme.md file
  [outputFormats.readme]
    baseName = "readme"
    mediaType = "text/markdown"
    isPlainText = true
    isHTML = false
    notAlternative = true
  # FixIt 0.3.10 | NEW Options to make output search.json file
  [outputFormats.search]
    baseName = "search"
    mediaType = "application/json"
    rel = "search"
    isPlainText = true
    isHTML = false
    permalinkable = true

[outputs]
  home = ["html", "rss", "archives", "offline", "search"]
  page = ["html", "markdown"]
  section = ["html", "rss"]
  taxonomy = ["html"]
  term = ["html", "rss"]

[taxonomies]
  tag = "tags"
  series = "series"
  category = "categories"
  collection = "collections"

[markup]
  [markup.highlight]
    codeFences = true
    lineNos = true
    lineNumbersInTable = true
    noClasses = false
    guessSyntax = true

[params]
  dateFormat = "2006-01-02"

  # FixIt 0.3.0 | NEW whether to add site subtitle to the title of index page
  # remember to set up your site subtitle by `params.header.subtitle.name`
  indexWithSubtitle = true
  # FixIt 0.3.13 | NEW whether to show summary in plain text
  summaryPlainify = true

  [params.author]
    name = "王章健"
    avatar = "/wang_256x256.jpg"

  [params.page.code]
    # 不显示代码编辑按钮
    edit = false
    # 代码块默认不折叠
    maxShownLines = -1

  [params.tagcloud]
    enable = true
    min = 14
    max = 32
    peakCount = 10
    orderby = "name"

  # FixIt 0.3.0 | NEW Archives page config (all pages of posts type)
  [params.archives]
    # special amount of posts in archives page
    paginate = 20
    # date format (month and day)
    dateFormat = "01-02"
  # Section page config (all pages in section)
  [params.section]
    # special amount of pages in each section page
    paginate = 20
    # date format (month and day)
    dateFormat = "01-02"
    # FixIt 0.3.10 | NEW Section feed config for RSS, Atom and JSON feed.
    [params.section.feed]
      # The number of posts to include in the feed. If set to -1, all posts.
      limit = -1
      # whether to show the full text content in feed.
      fullText = false

  # Term list (category or tag) page config
  [params.list]
    # special amount of posts in each list page
    paginate = 20
    # date format (month and day)
    dateFormat = "01-02"
    # FixIt 0.3.10 | NEW Term list feed config for RSS, Atom and JSON feed.
    [params.list.feed]
      # The number of posts to include in the feed. If set to -1, all posts.
      limit = -1
      # whether to show the full text content in feed.
      fullText = false

  # FixIt 0.3.13 | NEW recently updated pages config for archives, section and term list
  [params.recentlyUpdated]
    archives = true
    section = true
    list = true
    days = 30
    maxCount = 10

  # Header config
  [params.header]
    # FixIt 0.2.13 | CHANGED desktop header mode ["sticky", "normal", "auto"]
    desktopMode = "sticky"
    # FixIt 0.2.13 | CHANGED mobile header mode ["sticky", "normal", "auto"]
    mobileMode = "auto"
    # Header title config
    [params.header.title]
      # URL of the LOGO
      logo = "/web-app-manifest-512x512.png"
      # title name
      name = "rightsubtree"
      # whether to use typeit animation for title name
      typeit = false
    # FixIt 0.2.12 | NEW Header subtitle config
    [params.header.subtitle]
      # subtitle name
      name = "Per aspera ad astra"
      # whether to use typeit animation for subtitle name
      typeit = true

  # FixIt 0.2.18 | NEW Breadcrumb config
  [params.breadcrumb]
    enable = true
    sticky = false
    showHome = true
    # FixIt 0.3.13 | NEW
    separator = "/"
    capitalize = true

  # FixIt 0.3.10 | NEW Post navigation config
  [params.navigation]
    # whether to show the post navigation in section pages scope
    inSection = true
    # whether to reverse the next/previous post navigation order
    reverse = false

  # Footer config
  [params.footer]
    enable = true
    copyright = true
    author = true
    # FixIt 0.3.0 | NEW whether to show Hugo and theme info
    [params.footer.powered]
      enable = true
      hugoLogo = false
      themeLogo = false

  # Page config
  [params.page]
    # license info (HTML format is supported)
    license = ''
    # whether to show link to Raw Markdown content of the post
    linkToMarkdown = false
    # FixIt 0.3.0 | NEW whether to show link to view source code of the post
    linkToSource = false
    # FixIt 0.3.0 | NEW whether to show link to edit the post
    linkToEdit = false
    # FixIt 0.2.17 | NEW whether to enable readingTime
    readingTime = false

至此,我们已经在本地完成了blog系统的搭建,接下来要做的就是将本地文档上传到github,并检查Github Actions的自动构建结果;

 

三、Github自动构建和发布

我们的目标是,一旦完成github pages的搭建,后续我们只需要关心md文档,将md文档提交到github后,github能自动帮我们把网页生成好,维护好。这也是我们上面第一节创建Github Actions的目的所在;

我们需要向github pages repo 提交的内容,包括hugo的基础文件(包括主题)和我们自己写的md,其中前者一旦提交则相当长时间内是不需要改动的。而且,本地生成的public目录是不需要上传到github的(因为最终的文档是在github服务器上自动生成的);

所以,接下来需要做这些:

 

1、在repo里面添加 .gitignore 文件,内容必须包括这几行:

1
2
3
public/
.hugo_build.lock
**/.DS_Store

第二行内容是本地构建时生成的一个隐藏文件,第三行内容是mac系统上的隐藏系统文件(通常有图片的目录就很容易出现这个),哎,这一点mac挺烦的;

 

2、先仅仅添加这个.gitignore 文件并提交,如此则后续public目录就不会被提交了;

1
2
3
git add .gitignore
git commit -m "add .gitignore"
git push

 

3、添加hugo所有文件,以及本地的md文件;

1
2
3
git add .
git commit -m "add hugo files and md files"
git push

 

4、此时打开repo的“Actions” 页签,可以看到刚刚的提交触发了一次名为“Deploy Hugo site to Pages”的自动构建,且构建成功;【如果构建失败,网页是不会刷新的,所以每次push后最好还是检查一下构建结果】

Github Actions会自动使用commit msg作为本次workflow的描述,相当nice!

3-1

 

5、打开对应的 YourGitHubID.github.io ,就能看到md对应的网页了:

此时我们打开repo的Code页签,可以看到,这里列出的“代码”仍然仅包含我们git中的内容,并没有包括public目录,所以我们有理由猜测,用于github pages的public目录,是自动构建后存在于repo仓之外的位置的;

 

【自动build和deploy中遇到的问题】

FixIt主题某些页面对hugo的版本有依赖,需要较高版本的hugo,所以,如果发现Actions方式构建失败,那么就可以检查一下第一节添加的Actions的代码,确保Actions里面的环境和你本地保持一致。

 

Step1: 通过hugo version 命令查询本地版本:

3-4

 

Step2: 找到对应仓的Actions–Deploy Hugo site to Pages这个workflow,然后点击hugo.yml打开工作流对应的代码:

3-2

 

Step3: 将HUGO_VERSION 后面配置成跟你本地一样的数字即可;

3-3

 

四、自定义域名

 

1、首先确保你有权限修改选用域名的DNS记录,参考 github的文档

https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site

需要给选定的域名添加4条A记录

1
2
3
4
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153

4条AAAA记录:

1
2
3
4
2606:50c0:8000::153
2606:50c0:8001::153
2606:50c0:8002::153
2606:50c0:8003::153

一条CNAME记录;

 

以godaddy为例:

A记录的添加方法如下,注意name栏配置为@;

4-1

AAAA记录的添加方法如下:

4-2

CNAME记录的添加方法:

Name字段为www,值为github pages默认域名后面加一个点;

4-3

 

2、在github pages repo的settings页签的Pages栏,找到“Custom domain”项,输入你想配置的域名,然后点击Save按钮,github会开始检测,如果前面第一部分已经配置成功,则一般都会检测通过;

4-4

然后就可以在浏览器里面通过自定义域名访问到自己的blog了;

【DNS的修改通常需要几分钟到几小时才能生效,请耐心等待】

 

后续就能像写代码一样写blog了。

将md添加到 content/posts/ 目录,将图片等添加到 static目录,git push后,就能触发Github Actions自动做build和deploy了。

畅快且高效!

0%