Hugo 静态网站生成器

前言

一直想搭个自己的博客,记录一些技术思考和随笔杂记。要求很简单:

  • 📝 写 Markdown 就行,别折腾
  • 🆓 全程免费,不花一分钱
  • 🚦 推送代码后自动部署
  • 🌙 支持暗黑模式、代码高亮、目录
  • 🏷️ 支持标签、分类、RSS

最终选了 Hugo + PaperMod + Cloudflare Pages + GitHub Actions 这套方案。

整个过程从安装到上线大约 2 小时(主要是踩坑),下面是完整记录。

技术选型

对比了几个主流方案:

框架构建速度部署难度主题生态推荐度
Hugo⚡ 极快(Go 二进制)简单丰富(300+)⭐⭐⭐⭐⭐
Astro简单增长中⭐⭐⭐⭐
Hexo中(Node.js)简单丰富⭐⭐⭐⭐
Jekyll慢(Ruby)简单(GitHub Pages 原生)丰富⭐⭐⭐
Zola快(Rust)简单⭐⭐⭐

最终选 Hugo:单二进制零依赖,构建秒级完成,PaperMod 主题开箱即用,支持暗黑模式、TOC、代码高亮、RSS 等所有需求。

整体架构

 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
┌─────────────────────────────────────────────────────────┐
│                      你的本地电脑                         │
│                                                         │
│   写 Markdown 文章 → hugo new content/posts/xxx/index.md  │
│           ↓                                             │
│   hugo server -D 本地预览                                │
│           ↓                                             │
│   git add . && git commit && git push                    │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│                    GitHub 仓库                           │
│                                                         │
│   main 分支 push 触发 GitHub Actions                     │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│                  GitHub Actions CI                        │
│                                                         │
│   1. checkout 代码(含 submodule)                        │
│   2. 安装 Hugo extended                                 │
│   3. hugo --minify 构建静态资源                         │
│   4. 部署到 Cloudflare Pages                           │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│                  Cloudflare Pages                        │
│                                                         │
│   全球 CDN 加速,免费 SSL,自动分发                       │
│   访问地址:https://xiaohuang-blog.pages.dev              │
└─────────────────────────────────────────────────────────┘

全程自动化,你只需要 写文章 + push

项目结构

 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
my-blog/
├── .github/
│   └── workflows/
│       └── deploy.yml              # ⭐ GitHub Actions CI/CD 配置
├── archetypes/
│   └── default.md                 # 文章模板(新建文章自动套用)
├── assets/                        # 自定义 CSS/SCSS
├── content/                       # 📝 博客文章内容
│   └── posts/
│       ├── hello-world/
│       │   └── index.md           # 文章用 Bundle 方式管理
│       └── blog-setup-guide/
│           ├── index.md           # 文章本体
│           └── images/            # 文章配图(和文章同目录)
├── data/                          # 数据文件(导航、友链等)
├── layouts/                       # 模板覆盖(可选)
├── static/                        # 全站静态资源
│   ├── images/                    # 全站共用图片
│   └── favicon.ico               # 网站图标
├── themes/
│   └── PaperMod/                  # ⭐ 主题(git submodule)
├── .gitignore
├── .gitmodules                    # 子模块配置
├── hugo.toml                      # ⭐ Hugo 主配置文件
└── README.md

详细步骤

1. 安装 Hugo

1
2
3
4
5
6
# macOS
brew install hugo

# 验证(需要 extended 版支持 SCSS)
hugo version
# 输出:hugo v0.166.0+extended ...

2. 初始化项目

1
2
3
4
5
6
# 创建站点
hugo new site my-blog && cd my-blog
git init -b main

# 添加 PaperMod 主题
git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

3. 配置 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
baseURL = 'https://xiaohuang-blog.pages.dev'
languageCode = 'zh-CN'
title = '小黄的博客'
theme = 'PaperMod'

paginate = 10
enableRobotsTXT = true

[params]
  author = '小黄'
  description = '记录一些自己的思考,随笔杂记'
  defaultTheme = 'auto'          # auto 跟随系统 / dark / light
  ShowReadingTime = true          # 显示阅读时间
  ShowShareButtons = true         # 显示分享按钮
  ShowPostNavLinks = true         # 上一篇/下一篇
  ShowBreadCrumbs = true          # 面包屑导航
  ShowCodeCopyButtons = true      # 代码复制按钮
  ShowToc = true                  # 显示目录 TOC
  TocOpen = true                  # 默认展开目录

  # 首页 Profile 模式
  [params.profileMode]
    enabled = true
    title = '小黄的博客'
    subtitle = '记录一些自己的思考,随笔杂记'
    [[params.profileMode.buttons]]
      name = '📝 文章'
      url = '/posts'
    [[params.profileMode.buttons]]
      name = '🏷️ 标签'
      url = '/tags'

  # 社交链接
  [[params.socialIcons]]
    name = 'github'
    url = 'https://github.com/your-username'
  [[params.socialIcons]]
    name = 'rss'
    url = '/index.xml'

# 导航菜单
[menu]
  [[menu.main]]
    identifier = 'home'
    name = '🏠 首页'
    url = '/'
    weight = 10
  [[menu.main]]
    identifier = 'posts'
    name = '📝 文章'
    url = '/posts'
    weight = 20
  [[menu.main]]
    identifier = 'categories'
    name = '📂 分类'
    url = '/categories'
    weight = 30
  [[menu.main]]
    identifier = 'tags'
    name = '🏷️ 标签'
    url = '/tags'
    weight = 40

# 分类法
[taxonomies]
  category = 'categories'
  tag = 'tags'

# 代码高亮(Chroma)
[markup.highlight]
  codeFences = true
  guessSyntax = true
  lineNos = true                        # 显示行号
  noClasses = false                     # 使用 Chroma CSS(推荐)
  style = 'monokai'                     # 代码主题
  tabWidth = 4

# 输出格式(RSS)
[outputs]
  home = ['HTML', 'RSS', 'JSON']

4. 文章模板

archetypes/default.md

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
---
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
date: '{{ .Date }}'
draft: true                  # true=草稿,发布时改 false
toc: true                    # 显示目录
TocOpen: true               # 默认展开目录
description: ''              # 文章摘要(首页列表 + SEO)
tags: []                    # 标签
categories: []              # 分类
---

5. GitHub Actions 配置

.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
28
29
30
31
32
33
34
35
36
37
38
39
40
name: Build & Deploy to Cloudflare Pages

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read
  deployments: write

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.166.0'
          extended: true

      - name: Build
        run: hugo --minify

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/pages-action@v1
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          projectName: ${{ secrets.CLOUDFLARE_PROJECT_NAME }}
          directory: ./public
          gitHubToken: ${{ secrets.GITHUB_TOKEN }}
          branch: main

6. Cloudflare 配置

  1. 登录 Cloudflare Dashboard
  2. Workers & Pages → Create application → Pages → Create using direct upload
  3. 项目名:xiaohuang-blog
  4. 创建 API Token:My Profile → API Tokens → Create Custom Token
    • 权限:Account → Cloudflare Pages → Edit
  5. 获取 Account ID(右侧栏显示)

7. GitHub Secrets 配置

GitHub 仓库 → Settings → Secrets and variables → Actions:

NameValue
CLOUDFLARE_API_TOKENCloudflare API Token
CLOUDFLARE_ACCOUNT_IDCloudflare Account ID
CLOUDFLARE_PROJECT_NAMExiaohuang-blog

踩坑记录

坑 1:子模块缺失 .gitmodules

现象:Actions 报错 No url found for submodule path 'themes/PaperMod'

原因:用 git clone 而不是 git submodule add 拉取主题,缺少 .gitmodules 文件

解决:创建 .gitmodules

1
2
3
[submodule "themes/PaperMod"]
	path = themes/PaperMod
	url = https://github.com/adityatelange/hugo-PaperMod.git

坑 2:Wrangler 默认部署到 Workers

现象:部署后域名是 .workers.dev 而不是 .pages.dev

原因:Wrangler v4+ 默认把 Pages 部署到 Workers 平台

解决:通过 API 直接创建传统 Pages 项目:

1
2
3
curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/pages/projects" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name":"xiaohuang-blog","production_branch":"main"}'

坑 3:API Token 权限不足

现象Authentication error (401)

原因:Cloudflare 没有"Edit Cloudflare Pages"模板,自定义 Token 权限配置不对

解决:创建自定义 Token,权限必须包含 Account → Cloudflare Pages → Edit

坑 4:OAuth Token 无法创建 API Token

现象Unauthorized to access requested resource

原因:Wrangler 的 OAuth Token 权限有限,不能通过 API 创建新 Token

解决:只能在 Dashboard 手动创建 API Token

常见问题

图片怎么放?

Bundle 方式(推荐):图片和文章放同一目录

1
2
3
4
content/posts/my-post/
├── index.md
├── cover.jpg          ← 封面图
└── screenshot.png     ← 文中插图

文章中引用:

1
2
3
4
5
6
7
---
cover:
  image: cover.jpg
  alt: '封面描述'
---

![截图描述](screenshot.png)

全局方式:放 static/images/,引用 /images/photo.jpg

视频怎么放?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- HTML5 原生播放器 -->
<video controls width="100%" poster="cover.jpg">
  <source src="/videos/demo.mp4" type="video/mp4">
  您的浏览器不支持视频标签。
</video>

<!-- 第三方嵌入(推荐) -->
<iframe src="//player.bilibili.com/player.html?bvid=BVxxxxxx"
        width="100%" height="480" frameborder="0" allowfullscreen>
</iframe>

新建文章后本地预览

1
2
hugo server -D        # -D 包含草稿文章
# 浏览器打开 http://localhost:1313

发布文章

把 Front Matter 中 draft: true 改为 draft: false,然后 push 即可。

日常使用手册

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 1. 新建文章
hugo new content/posts/文章标题/index.md

# 2. 编辑内容(把 draft 改为 false)
vim content/posts/文章标题/index.md

# 3. 本地预览
hugo server -D

# 4. 提交推送(自动触发构建 + 部署)
git add .
git commit -m "post: 文章标题"
git push

# 等 1-2 分钟,访问 https://xiaohuang-blog.pages.dev 查看效果

总结

项目方案
静态生成Hugo (Go)
主题PaperMod
代码托管GitHub
CI/CDGitHub Actions
部署Cloudflare Pages
费用0 元
构建时间~100ms
部署时间~30s
功能暗黑模式、代码高亮、TOC、标签、分类、RSS

整套方案零成本、自动化、维护低。你只需要专注于写 Markdown 文章,剩下的全部自动化 ✨