前言

本教程详细说明如何使用 Hugo + GitHub Pages + Paper Mod 主题来部署网站,通过私有仓库管理源码,公开仓库发布网站。

最终仓库结构如下所示:

私有仓库 (hugo-source)

├── content/
│   └── posts/
│       └── hello-world.md    # 原始文章
├── themes/
├── hugo.yaml
└── public/                   # 这个文件夹是一个独立的 git 仓库
    ├── index.html           # 构建后的文件
    ├── posts/
    │   └── hello-world/
    │       └── index.html   # 构建后的文章
    └── ...

公开仓库 (username.github.io)

├── index.html               # 与 public 文件夹中的文件相同
├── posts/
│   └── hello-world/
│       └── index.html
└── ...

步骤

1. 创建两个 GitHub 仓库

- 私有仓库:hugo-source (用于存放源码)
- 公开仓库:username.github.io (用于发布网站)

2. 安装必要工具

# 安装 Hugo (以 Ubuntu 为例)
# sudo apt install hugo
# 安装 Hugo (以 Mac 为例)
brew install hugo

# 验证安装
hugo version

3. 创建新的 Hugo 站点

# 创建新站点, --format yaml 指定hugo 配置文件使用 yaml 格式,默认是toml格式
hugo new site /Users/yourname/Documents/hugo-source --format yaml
cd /Users/yourname/Documents/hugo-source

# 初始化 git 仓库
git init

4. 安装 PaperMod 主题

git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
git submodule update --init --recursive # needed when you reclone your repo (submodules may not get cloned automatically)

5. 配置 hugo.yaml

baseURL: https://username.github.io/
languageCode: en-us
title: My Blog
theme: PaperMod

# 基础设置
enableGitInfo: false
enableEmoji: true # 支持 emoji 显示
paginate: 10 # 一页显示10篇文章

# params底下的应该是PaperMod的设置
params:
  homeInfoParams:
    Title: "👋 Welcome to My Blog"
    Content: "Hi, this is my blog."
  
  socialIcons:
    - name: "rss"
      url: "/index.xml"
    - name: "email"
      url: "[email protected]"
    - name: "github"
      url: "https://github.com/username"


  label:
    text: "User's Blog"
    icon: /favicon.ico  # 导航栏显示的图标
    iconHeight: 35  # 控制导航栏图标大小

  assets:
    disableHLJS: true
    favicon: "/favicon.ico"
    favicon16x16: "/favicon-16x16.png"
    favicon32x32: "/favicon-32x32.png"
    # apple_touch_icon: "/apple-touch-icon.png"
    # android_chrome_192: "/android-chrome-192x192.png"
    # android_chrome_512: "/android-chrome-512x512.png"

  env: production
  defaultTheme: auto
  disableSpecial1stPost: true
  ShowRssButtonInSectionTermList: true
  ShowToc: true
  # 文章设置
  ShowReadingTime: false # 显示阅读时间
  ShowPostNavLinks: true
  ShowBreadCrumbs: true
  ShowCodeCopyButtons: true
  ShowWordCount: true # 显示字数统计
  ShowAuthor: true # 显示作者

menu:
  main:
    - name: Posts
      url: /posts/
      weight: 1
    - name: Archive
      url: /archive/
      weight: 2
    - name: Search
      url: /search/
      weight: 3
    - name: Tags
      url: /tags/
      weight: 4

# 输出设置
outputs:
  home:
    - HTML
    - RSS
    - JSON # 用于搜索功能
  section:
    - HTML


# 文章页面设置
permalinks:
  posts: /posts/:year-:month-:day-:filename/

# Markdown 渲染设置
markup:
  goldmark:
    renderer:
      unsafe: true

6. 配置搜索和归档功能

为了确保搜索功能正常工作,创建 content/search.md

---
title: "Search"
layout: "search"
---

还需要创建 content/archive.md

---
title: "Archive"
layout: "archives"
url: "/archive/"
summary: archives
---

7. 自定义浏览器标签栏图标

  1. 选择你喜欢的图片,在 favicon.io 网站上生成 favicon

  2. 将生成的文件下载并替换到 static 目录下, 结构如下:

hugo-source/
├── content/
├── static/
│   ├── android-chrome-192x192.png  # Android Chrome 浏览器图标(中尺寸)
│   ├── android-chrome-512x512.png  # Android Chrome 浏览器图标(大尺寸)
│   ├── apple-touch-icon.png       # iOS/macOS 设备图标 (180x180)
│   ├── favicon-16x16.png          # 小尺寸网站图标
│   ├── favicon-32x32.png          # 标准网站图标
│   └── favicon.ico                # 基础网站图标(兼容性)
...
└── hugo.yaml

8. 创建第一篇文章

# 创建新文章
hugo new posts/hello-world/index.md

编辑 content/posts/hello-world/index.md:

---
title: "Hello World"
date: 2024-11-10
draft: false
tags: ["test"]
---

This is my first post!

本地预览(可选):

hugo server # 如果文章设置的draft 为true, 则需要加上 -D 参数用于启用草稿模式,即 draft 为 true 的文章也会被预览

9. 设置部署工作流

hugo-source 仓库中创建文件 .github/workflows/deploy.yaml:

name: Deploy Hugo site to Pages

on:
  push:
    branches:
      - main
  workflow_dispatch:  # 允许手动触发

# 设置并发部署策略
concurrency:
  group: "pages"
  cancel-in-progress: false

# 默认使用 bash
defaults:
  run:
    shell: bash

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    env:
      HUGO_VERSION: 0.138.0  # 指定 Hugo 版本
    
    steps:
      # 安装 Hugo
      - name: Install Hugo CLI
        run: |
          wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
          && sudo dpkg -i ${{ runner.temp }}/hugo.deb          

      # 安装 Dart Sass(如果需要)
      - name: Install Dart Sass
        run: sudo snap install dart-sass
      
      # 检出代码
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive  # 获取子模块
          fetch-depth: 0        # 获取完整的 git 历史

      # 安装 Node.js 依赖(如果需要)
      - name: Install Node.js dependencies
        run: |
          if [[ -f package-lock.json || -f npm-shrinkwrap.json ]]; then
            npm ci
          fi          

      # 构建 Hugo 站点
      - name: Build with Hugo
        env:
          HUGO_ENVIRONMENT: production
          TZ: Asia/Shanghai  # 设置时区
        run: |
          hugo \
            --gc \
            --minify \
            --baseURL "https://username.github.io/"  # 替换为你的 URL          

      # 部署到外部仓库
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
          external_repository: username/username.github.io  # 替换为你的外部仓库
          publish_branch: main
          publish_dir: ./public
          #cname: your-custom-domain.com  # 添加这一行,替换为你的域名,避免每次deploy后都要手动更新CNAME文件
          commit_message: ${{ github.event.head_commit.message }}
          user_name: 'github-actions[bot]'
          user_email: 'github-actions[bot]@users.noreply.github.com'

10. 折叠长代码块

  1. assets/css/extended/custom.css 文件中添加以下代码:

    /* 折叠代码块 */
    .collapse-wrapper {
        margin: 1rem 0;
    }
    
    .collapse-button {
        width: 100%;
        padding: 0.5rem;
        background-color: var(--border);
        border: none;
        cursor: pointer;
        text-align: left;
        font-size: 0.9rem;
    }
    
    .collapse-button:hover {
        background-color: var(--border-hover);
    }
    
    .collapse-content {
        display: none;
        padding: 1rem;
        border: 1px solid var(--border);
    }
    
    .collapse-wrapper.active .collapse-content {
        display: block;
    }
    
    /* 暗色主题适配 */
    [theme="dark"] .collapse-button {
        background-color: var(--entry);
        color: var(--primary);
    }
    
    [theme="dark"] .collapse-button:hover {
        background-color: var(--border);
    } 
    
    /* 折叠代码块 结束 */
    

  2. layouts/shortcodes/detail-tag.html 文件中添加以下代码:

{{ $_hugo_config := `{ "version": 1 }` }}
<div class="collapse-wrapper">
    <button class="collapse-button" onclick="this.parentElement.classList.toggle('active')">
        {{ with .Get "summary" }}{{ . }}{{ else }}点击展开{{ end }}
        <span class="collapse-icon">▼</span>
    </button>
    <div class="collapse-content">
        {{ .Inner | markdownify }}
    </div>
</div>
  1. 在写markdown时,使用如下代码包裹需要折叠的代码块:
{‎{< detail-tag summary="点击查看" >}}
```python
Long code block
```
{‎{< /detail-tag >}}

11. 设置部署密钥

  1. 首先生成 SSH 密钥对
# 在本地终端执行
ssh-keygen -t rsa -b 4096 -C "[email protected]" -f gh-pages

这会生成两个文件:

  • gh-pages(私钥)
  • gh-pages.pub(公钥)
  1. 在私有仓库 (hugo-source) 添加私钥

    • 打开私有仓库的 Settings
    • 点击左侧的 “Secrets and variables” -> “Actions”
    • 点击 “New repository secret”
    • Name 填写:ACTIONS_DEPLOY_KEY
    • Secret 填写:复制 gh-pages 文件的全部内容(私钥)
    • 点击 “Add secret”
  2. 在公开仓库 (username.github.io) 添加公钥

    • 打开公开仓库的 Settings
    • 点击左侧的 “Deploy keys”
    • 点击 “Add deploy key”
    • Title 填写:HUGO_DEPLOY_KEY(或其他描述性名称)
    • Key 填写:复制 gh-pages.pub 文件的全部内容(公钥)
    • 勾选 “Allow write access”
    • 点击 “Add key”

注意

  1. 密钥生成后要立即妥善保管,特别是私钥部分
  2. 确保将完整的密钥内容复制,包括开头的 -----BEGIN... 和结尾的 -----END...
  3. 添加后可以删除本地的 gh-pagesgh-pages.pub 文件

这样设置后,GitHub Actions 就能安全地将构建的内容部署到公开仓库了。

12. 初始化和推送源码仓库

# 在 hugo-source 目录下
git add .
git commit -m "Initial commit"
# git branch -M main #(如果需要)
git remote add origin [email protected]:username/hugo-source.git
git push -u origin main

13. 完成设置

  • 等待 GitHub Actions 完成部署
  • 访问 https://username.github.io 查看你的网站

维护网站的工作流程

  1. 在本地 hugo-source 目录中编写新文章:
hugo new posts/new-post/index.md
  1. 编辑文章内容, 如果使用cursor,可以直接在 content/posts/new-post/index.md 文件中复制粘贴图片,cursor会自动将图片保存到 content/posts/new-post/下。

  2. 本地预览(可选):

hugo server # 如果文章设置的draft 为true, 则需要加上 -D 参数用于启用草稿模式,即 draft 为 true 的文章也会被预览
  1. 提交和推送更改:
git add .
git commit -m "Add new post"
git push origin main
  1. GitHub Actions 会自动部署更新后的内容到你的网站

使用自定义域名

如果想隐藏真实的username.github.io,可以参考隐藏真实的xxx.github.io一文, 而跳过下面的配置。

如果你想使用自定义域名(如 user.me),需要完成以下配置:

  1. GitHub Pages 配置

    • 在前面的 deploy.yaml 文件中取消注释并修改 cname 参数:
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          # ... 其他配置 ...
          cname: www.user.me  # 取消注释并修改为你的域名
      

    这样可以避免每次部署后手动更新 CNAME 文件。

  2. Cloudflare DNS 配置

    • 添加以下 DNS 记录(全部设置为 “仅 DNS”,不使用代理):

      # 配置 www 子域名
      CNAME  www    username.github.io
      
      # 配置根域名 A 记录
      A      @      185.199.108.153
      A      @      185.199.109.153
      A      @      185.199.110.153
      A      @      185.199.111.153
      
    • 添加页面规则:

      1. 点击 “规则” -> “模版” -> “从 WWW 重定向到根”
      2. 选择通配符模式
      3. 在 请求 URL 输入:https://user.me/*
      4. 目标 URL 设置为:
        • 目标 URL:https://www.user.me/${1}
        • 转发类型:301 (永久重定向)
      5. 点击 “保存”

      这样设置可以确保所有访问 www 子域名的请求都会被永久重定向到根域名,有助于 SEO 优化和避免重复内容问题。

  3. Cloudflare SSL 配置

    • 在 SSL/TLS 设置中选择 “Full” 模式
    • 这样配置后,你就可以在 GitHub Pages 中启用 “Enforce HTTPS” 选项

完成以上设置后,访问者可以通过 https://www.user.mehttps://user.me 访问你的网站。

注意事项

  1. username 替换为你的 GitHub 用户名
  2. 确保在 GitHub 上正确配置了 SSH 密钥
  3. 私有仓库中的 public 目录应该被添加到 .gitignore
  4. 为了保护隐私,建议使用 ExifTool 工具清除图片中的元数据(metadata)。这些元数据可能包含设备信息、拍摄位置等敏感信息(参考链接):
    # 安装 ExifTool
    brew install exiftool
    
    # 清除指定目录下所有图片的元数据(会直接覆盖原文件)
    exiftool -a -all:all= -r 图片目录路径 -overwrite_original
    

总结

这样设置后,你就可以在私有仓库中管理网站源码,而生成的静态文件会自动部署到公开仓库中展示。这种方式既保护了源码,又能享受 GitHub Pages 的免费托管服务。