目录

利用 Hugo 和 Github Pages 创建静态博客并实现自动部署

由于一直想创建一个属于自己的博客,但是一直没有找到合适的平台,所以最近开始尝试利用 Hugo 和 Github Pages 创建一个静态博客。Hugo 可以很大程度上解决我的一个个人需求:我不希望直接将我的.md文件上传到 Github 上,这样别人就会直接拿到我的笔记和代码,而我希望的是别人只能看到我写的博客。

期间也踩坑了很多次,看了非常多的经验帖,最后花费了两天时间终于大功告成!

看到这么好看的主页,一切都是值得的(^_^)。

1. 环境准备

1.1 下载Go

Hugo 是用 go 写的,所以速度很快,因此在下载Hugo 之前还得本地配置 go 环境

1.2 下载Hugo

2. 创建博客

2.1 初始化博客

通过hugo new site Blog命令初始化一个 Blog/目录,里面会自动生成一些框架代码

1
2
3
4
5
6
7
8
9
└─Blog
    ├─archetypes
    ├─assets
    ├─content
    ├─data
    ├─i18n
    ├─layouts
    ├─static
    └─themes

2.2 下载主题

打开 hugo theme 的网站,选择合适的主题,以LoveIt 举例。 Hugo Themes: https://themes.gohugo.io

LoveIt 主题的仓库是: https://github.com/dillonzq/LoveIt.

你可以下载主题的 发布版本 .zip 文件 并且解压放到 themes 目录.

另外, 也可以直接把这个主题克隆到 themes 目录:

1
git clone https://github.com/dillonzq/LoveIt.git themes/LoveIt

或者, 初始化你的项目目录为 git 仓库, 并且把主题仓库作为你的网站目录的子模块:

1
2
git init
git submodule add https://github.com/dillonzq/LoveIt.git themes/LoveIt

主题的兼容性

LoveIt 分支或版本 支持的 Hugo 版本
master(不稳定) ≥ 0.128.0
0.3.X(推荐) 0.128.0 - 0.145.0
0.2.X(过时) 0.68.0 - 0.127.0

3. 配置

这里是关键步骤,虽然有点不求甚解,但是真的能够省很多功夫,问题就是后期修改需要经常去翻LoveIt的官方文档。

3.1 文件替换

myblog/themes/LoveIt/exampleSite路径下的所有文件直接复制到myblog/覆盖掉。

其中:

  • assets存放全局资源
  • content存放md文件,即你的文章
  • static存放静态资源
  • config.toml为博客配置文件

注:这里我踩坑了非常多的时间,标签和分类功能一直显示找不到这个pages,其实最后发现就是content/目录下不是只有posts/就够了,还需要有about/,categories/,tags/文件夹,才能让标签、分类功能生效,这里最好的方法其实就是把myblog/themes/LoveIt/exampleSite/content里面的所有内容都复制到myblog/content/里

完成上面这步应该就能实现跟LoveIt官网一模一样的效果了。

使用hugo serve命令启动网站来看看效果吧。

3.2 参数修改

下面就是把config.toml配置文件里面的一些参数改成自己想要的了

自己看着改就行

4. 部署到 Github

4.1 手动部署

在 Hugo 网站文件夹的根目录(\Blog)下执行 hugo 命令构建

Hugo 会将构建的网站内容默认保存至网站根目录下的 public/ 文件夹下

你只需要每次将 public/ 文件夹里的内容推送到 Github 仓库即可部署成功

4.2 使用Github Actions自动发布网站

手动部署策略每次都得自己生成静态网站然后推送到仓库,有点太麻烦了。

相较于手动发布网站,用Github Actions自动发布网站达成的效果是,每次需更新网站时,只需将Blog文件夹上传到hugo-blog仓库中,之后Github自动就会更新<username>.github.io仓库中的内容,无需手动将public文件夹上传到<username>.github.io仓库中。

这里的 hugo-blog 仓库可以配置成 private,因为你的 .md 文件都在这里

4.2.1 创建access tokens

打开Github网页,点击右上角个人头像,进入Settings界面,点击设置列表中的Developer settings

image-20250625234612169

点击Personal access tokens下的Tokens(classic),然后点击Generate new token下的Generate new token(classic)

/%E5%88%A9%E7%94%A8-hugo-%E5%92%8C-github-pages-%E5%88%9B%E5%BB%BA%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2%E5%B9%B6%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/images/image-20250626001837636.png
image-20250626001837636

生成access token时,勾选workflow,同时把 Expiration 的时间设置为永不过期

/%E5%88%A9%E7%94%A8-hugo-%E5%92%8C-github-pages-%E5%88%9B%E5%BB%BA%E9%9D%99%E6%80%81%E5%8D%9A%E5%AE%A2%E5%B9%B6%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/images/image-20250626002003275.png
image-20250626002003275

最后点击页面下方的Generate token按钮即可。生成完成后如下图,将生成的access token复制下来,以后这个aceess token将不可见。

image-20250625234829616
4.2.2 创建Actions Secret

进入到上面提到的hugo-blog仓库,依次点击SettingsSecrets and VariablesActionsNew repository secret

image-20250625234914398

如下图,输入NameSecretName可自定义,这里取名为HUGO_TOKENSecret即为上面生成的access token

image-20250625234950329

最后点击Add secret完成。

4.2.3 创建Github Action

.github/workflows文件夹下创建一个yaml文件,比如.github/workflows/hugo_deploy.yaml,文件的内容如下:

 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
name: GitHub Pages

on:
  push:
    branches:
      - master
  pull_request:

jobs:
  deploy:
    # 这里指定ubuntu为指定版本, 比如 ubuntu-22.04
    runs-on: ubuntu-22.04
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref }}
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          # 运行hugo version可以查看本地hugo版本
          # 这里使用最新版本的hugo, 也可写具体的版本号, 与本地hugo版本保持一致, 比如 0.138.0
          hugo-version: 0.145.0
          # 查看hugo version的结果,如果本地是extended版本,就设置成true,反之设置成false
          extended: false

      - name: Build
        run: cd Blog && hugo -D # 命令可以修改,比如草稿文章也想发表可改成hugo -D

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        if: github.ref == 'refs/heads/master'
        with:
          # HUGO_TOKEN就是上面Actions Secret取的名字,要与自己取的名字保持一致
          personal_token: ${{ secrets.HUGO_TOKEN }}
          # <username>替换成自己的用户名
          external_repository: ThisingL/thisingl.github.io
          # 现在默认分支都用main,比如用的是master分支,则改为master
          publish_branch: master
          publish_dir: ./Blog/public
          # 可选配置, 每次博客更新后, 本仓库会自动往<username>.github.io仓库提交一次更新后的网站内容
          # 添加该项配置后, <username>.github.io仓库的提交信息就会使用本仓库的提交信息
          commit_message: ${{ github.event.head_commit.message }}
          # cname: https://huxinme.top  # 填写自己的自定义域名, 如果没有自定义域名, 删除该项配置
4.2.4 发布网站

publicresources文件夹都是Hugo生成静态网站时创建的,因此在.gitignore文件中可以添加以下内容

1
2
3
.hugo_build.lock
/public/*
/resources/  # hugo生成的文件,也可忽略

最后,将Blog文件夹提交到hugo-blog仓库中即可。

提交到Github上后,稍等一会儿,打开<username>.github.io就可以看到更新后的网站了。

5. 日常使用流程

  1. 使用命令hugo new posts/新笔记/新笔记.md, 在 content\posts\目录下新建文件夹 新笔记,文件夹下新建 新笔记.md文件,文件图片放在 新笔记\images\ 文件夹下,这样在typora中设置图片位置为 ./images即可。这里还需要创建一个新笔记posts/新笔记/新笔记.md,由于 Hugo 在渲染 Markdown 文档时会根据 _/*/>> 之类的语法生成 HTML 文档, 并且有些转义字符形式的文本内容 (如 \(/\)/\[/\]/\\) 会自动进行转义处理, 因此需要对这些地方进行额外的转义字符表达来实现自动渲染。所以一个好的解决方法是:多行公式前使用<div>标签,但是这个就会带来一个新问题:Typora中不好看公式了。因此就可以每次在posts/新笔记/新笔记.md中进行笔记书写,然后使用我下面提供的shell脚本来将新笔记.md复制到posts/新笔记/index.md中将行间公式前统一加上 <div>标签。
  2. 这里我写了一个单行shell脚本,可以一件把将新笔记.md生成符合hugo要求的index.md,直接复制到bash里运行就可以了
image-20250627161644775
1
2
3
4
5
6
7
find . -maxdepth 1 -name "*.md" ! -name "index.md" -print > tmp_list && \
file_count=$(wc -l < tmp_list) && \
if [ "$file_count" -eq 0 ]; then echo "错误:未找到任何非index.md的.md文件" && rm tmp_list; \
elif [ "$file_count" -gt 1 ]; then echo "错误:找到多个非index.md的.md文件:" && cat tmp_list && rm tmp_list; \
else target_file=$(head -n1 tmp_list) && echo "正在处理文件: $target_file" && \
awk 'BEGIN {in_math=0} {line=$0; output=""; while(match(line, /\$\$/)) {pre=substr(line,1,RSTART-1); rest=substr(line,RSTART); if(in_math==0) {output=output pre "<div>$$"; in_math=1} else {output=output pre "$$"; in_math=0} line=substr(rest,3)} output=output line; print output}' "$target_file" > index.md && \
echo "已将处理后的内容写入 index.md" && rm tmp_list; fi
  1. 将更新 git pushhugo-blog仓库中,网站便更新完毕。

注:这里还有一个坑,参考了Hugo 博客插入图片的方法 | Cassius’s Blog

由于 Hugo 生成的是静态博客,因此插入图片是一件相对比较麻烦的事情。当然,一个简单的方法就是采用图床,不过大部分图床都需要收费,免费的也不能保证稳定性,而我们的博客所用的图片数量也并不算多,所以我们可以采取随 markdown 源文件一起存储的方法。

Hugo 普遍的新建博文的方式是 hugo new posts/new-post.md,这样我们可以将图片都存放在 Blog/static/ 目录下,这样经过编译之后图片会存放到网站的根目录。不过如果这样,那么在编写博客的时候编辑器就没办法显示图片,只能凭感觉了。而放到其他目录时,编译后的网站又不能识别。

一个较为优雅的方式就是

1
hugo new posts/new-post/index.md

将新的博文创建成一个文件夹,将 markdown 源文件命名为 index.md,再在文件夹内创建 pics 文件夹,将图片放入该文件夹,在编写博文插入图片时使用相对路径,即 pics/1.png,这样在编辑器中就可以看到图片了。

而当网站编译完成之后,文件夹的格式就会如下所示

  • first-post
    • pics
      • 1.png
    • index.html

index.html 文件与 pics 文件夹同级,网站同样也可以识别 html 文件中的图片路径。

这里一定要命名为index.md,不可以命名为 新笔记.md,不然你会发现编译后网站图片位置就不再同级网站文件夹下了,上面操作也就会失效(这里花了我起码2小时来发现这个bug所在)