USERNAME、SOURCE_REPO、THEME_NAME、THEME_REPO_URL 实际操作时,替换成自己的 GitHub 用户名、源码仓名称和主题信息。
一、部署结构
推荐使用双仓库结构:
| 仓库 | 职责 |
|---|---|
USERNAME/SOURCE_REPO | 保存 Hugo 源码、文章、主题、配置和 GitHub Actions |
USERNAME/USERNAME.github.io | 保存 Hugo 构建后的静态文件,由 GitHub Pages 对外发布 |
发布链路是:
本地写文章
-> 推送到 SOURCE_REPO
-> GitHub Actions 构建 Hugo
-> 同步 public/ 到 USERNAME.github.io
-> GitHub Pages 发布网站
这种方式的优点是:
- 源码仓可以公开,也可以私有。
- Pages 仓库只保存构建产物,不混入草稿、主题源码和工作流。
- 发布动作可重复、可审计,出问题时直接看 GitHub Actions 日志。
如果你的源码也准备完全公开,也可以只用一个仓库,通过 GitHub Pages 的 Actions artifact 发布。本文聚焦双仓库方案,因为它更适合把源码和发布结果分开维护。
二、准备工作
需要准备:
- GitHub 账号:
USERNAME。 - Hugo 源码仓:
SOURCE_REPO。 - GitHub Pages 仓:
USERNAME.github.io。 - 本地 Git。
- 本地 Hugo。建议使用 Hugo Extended,尤其是主题依赖 SCSS 或 Hugo Pipes 时。
- 一把专门给 GitHub Actions 使用的 SSH Deploy Key。
版本原则:
- 不在教程里硬编码 Hugo 版本。
- 本地和 CI 使用同一种安装策略,避免本地能构建、CI 构建失败。
- 如果团队或个人项目需要完全可复现,可以在自己的仓库里固定 Hugo 版本,但教程模板应保持通用。
三、三平台本地环境
macOS
使用 Homebrew 安装:
brew install git hugo
检查命令是否可用:
git --version
hugo version
克隆源码仓:
git clone --recurse-submodules https://github.com/USERNAME/SOURCE_REPO.git
cd SOURCE_REPO
hugo server --buildDrafts --buildFuture
如果克隆时忘记拉主题子模块:
git submodule update --init --recursive
Linux
Debian / Ubuntu 可以使用系统包管理器:
sudo apt update
sudo apt install git hugo
Fedora 可以使用:
sudo dnf install git hugo
Arch Linux 可以使用:
sudo pacman -S git hugo
如果发行版软件源里的 Hugo 太旧,或主题明确要求 Hugo Extended,优先使用 Hugo 官方安装方式或发行版支持的新版包源。安装后检查:
git --version
hugo version
克隆并启动本地预览:
git clone --recurse-submodules https://github.com/USERNAME/SOURCE_REPO.git
cd SOURCE_REPO
hugo server --buildDrafts --buildFuture
Windows
推荐使用 PowerShell。
使用 winget:
winget install Git.Git
winget install Hugo.Hugo.Extended
也可以使用 Scoop:
scoop install git
scoop install hugo-extended
检查命令是否可用:
git --version
hugo version
克隆并启动本地预览:
git clone --recurse-submodules https://github.com/USERNAME/SOURCE_REPO.git
cd SOURCE_REPO
hugo server --buildDrafts --buildFuture
如果主题没有拉下来:
git submodule update --init --recursive
Windows 本地开发不需要额外安装 rsync。后面部署用到的 rsync 会在 GitHub Actions 的 Linux 环境里执行。
四、创建 Hugo 站点
新建 Hugo 站点:
hugo new site SOURCE_REPO
cd SOURCE_REPO
git init
添加主题。多数 Hugo 主题都可以作为 Git submodule 引入:
git submodule add THEME_REPO_URL themes/THEME_NAME
THEME_REPO_URL 是主题仓库地址,THEME_NAME 是 themes/ 目录下的主题目录名。
推荐的基础目录结构:
SOURCE_REPO/
├── hugo.toml
├── archetypes/
├── assets/
├── content/
│ ├── about.md
│ └── post/
├── layouts/
├── static/
├── themes/
│ └── THEME_NAME/
└── .github/
└── workflows/
常用目录说明:
content/post/:博客文章。assets/:需要被 Hugo 处理的资源,比如可压缩、裁剪、指纹化的图片或脚本。static/:原样复制到站点根目录的文件,比如附件、图标、验证文件。layouts/:自定义或覆盖主题模板。themes/THEME_NAME/:主题目录。
五、配置 Hugo
打开 hugo.toml,写入最小配置:
baseURL = 'https://USERNAME.github.io/'
languageCode = 'zh-CN'
title = 'My Blog'
theme = 'THEME_NAME'
timeZone = 'Asia/Shanghai'
如果你部署的是用户主页,baseURL 使用:
baseURL = 'https://USERNAME.github.io/'
如果你部署的是项目页,baseURL 通常使用:
baseURL = 'https://USERNAME.github.io/REPOSITORY_NAME/'
几个关键点:
theme必须等于themes/下的主题目录名。baseURL必须和最终访问地址一致,否则容易出现样式、图片、脚本路径错误。- 如果主题提供额外配置文件,优先按主题文档放到
config/或hugo.toml中,不要为了“看起来完整”复制无关配置。
创建第一篇文章:
hugo new content/post/my-first-post.md
本地预览:
hugo server --buildDrafts --buildFuture
确认没有问题后,本地构建一次:
hugo --minify --cleanDestinationDir
构建结果会输出到 public/。
六、创建 GitHub 仓库
创建源码仓:
USERNAME/SOURCE_REPO
创建 Pages 仓:
USERNAME/USERNAME.github.io
Pages 仓库进入 Settings -> Pages,选择:
- Source:
Deploy from a branch - Branch:
main - Folder:
/root
源码仓推送:
git add .
git commit -m "init hugo site"
git branch -M main
git remote add origin https://github.com/USERNAME/SOURCE_REPO.git
git push -u origin main
如果你已经在 GitHub 创建仓库并选择了 SSH 地址,也可以把 remote 改成 SSH:
git remote set-url origin git@github.com:USERNAME/SOURCE_REPO.git
七、配置 SSH Deploy Key
源码仓的 GitHub Actions 需要把 public/ 推送到 USERNAME.github.io。最简单的做法是给 Pages 仓库配置一把带写权限的 Deploy Key,再把私钥放进源码仓的 Actions Secret。
macOS / Linux
生成 key:
ssh-keygen -t ed25519 -C "hugo pages deploy" -f ~/.ssh/hugo_pages_deploy
查看公钥:
cat ~/.ssh/hugo_pages_deploy.pub
查看私钥:
cat ~/.ssh/hugo_pages_deploy
Windows
PowerShell 中生成 key:
ssh-keygen -t ed25519 -C "hugo pages deploy" -f "$env:USERPROFILE\.ssh\hugo_pages_deploy"
查看公钥:
Get-Content "$env:USERPROFILE\.ssh\hugo_pages_deploy.pub"
查看私钥:
Get-Content "$env:USERPROFILE\.ssh\hugo_pages_deploy" -Raw
GitHub 中的配置
在 USERNAME/USERNAME.github.io 仓库中:
- 打开
Settings。 - 进入
Deploy keys。 - 添加公钥。
- 勾选
Allow write access。
在 USERNAME/SOURCE_REPO 仓库中:
- 打开
Settings。 - 进入
Secrets and variables->Actions。 - 新增 Repository secret。
- 名称填写
DEPLOY_KEY。 - 内容填写私钥完整内容。
不要把私钥提交到任何 Git 仓库。
八、配置 GitHub Actions
在源码仓创建 .github/workflows/deploy.yml。
下面是通用模板。CHECKOUT_ACTION_REF 是 actions/checkout 的引用占位符,实际使用时请按 GitHub 官方文档选择稳定引用;如果你希望完全固定构建环境,也可以在自己的仓库中固定 Hugo 安装方式。
name: Deploy Hugo Site
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@CHECKOUT_ACTION_REF
with:
submodules: recursive
- name: Install tools
run: |
sudo apt-get update
sudo apt-get install -y hugo rsync
hugo version
- name: Build site
run: hugo --minify --cleanDestinationDir
- name: Configure SSH
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
install -d -m 700 ~/.ssh
printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Publish static files
env:
DEPLOY_REPO: git@github.com:USERNAME/USERNAME.github.io.git
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_SSH_COMMAND: ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=~/.ssh/known_hosts
run: |
deploy_dir="$(mktemp -d)"
git clone "$DEPLOY_REPO" "$deploy_dir"
git -C "$deploy_dir" checkout -B main
rsync -a --delete --exclude '.git' public/ "$deploy_dir/"
touch "$deploy_dir/.nojekyll"
git -C "$deploy_dir" add -A
if git -C "$deploy_dir" diff --cached --quiet; then
echo "No changes to publish"
exit 0
fi
git -C "$deploy_dir" commit -m "deploy: ${GITHUB_SHA}"
git -C "$deploy_dir" push origin main
这个 workflow 的职责:
- 拉取源码和主题子模块。
- 安装 Hugo 与同步工具。
- 构建站点到
public/。 - 从
DEPLOY_KEY写入 SSH 私钥。 - 克隆
USERNAME.github.io。 - 用
rsync --delete同步静态文件。 - 写入
.nojekyll,避免 GitHub Pages 用 Jekyll 规则处理文件。 - 有变化才提交,没有变化就直接退出。
如果你的主题必须使用 Hugo Extended,而系统包安装的 Hugo 不满足要求,把 Install tools 步骤替换为官方推荐的 Hugo Extended 安装方式。原则是:本地怎么验证,CI 就尽量怎么安装。
九、日常写作流程
新建文章:
hugo new content/post/my-new-post.md
文章 front matter 可以参考:
---
title: 文章标题
date: YYYY-MM-DDTHH:mm:ss+08:00
draft: false
tags:
- Hugo
categories:
- 博客搭建
---
本地预览:
hugo server --buildDrafts --buildFuture
构建检查:
hugo --minify --cleanDestinationDir
提交并推送源码仓:
git add .
git commit -m "post: add new article"
git push origin main
推送后进入源码仓的 Actions 页面查看部署状态。部署成功后,Pages 仓库会出现由 github-actions[bot] 创建的部署提交。
十、常见问题
本地提示找不到主题
通常是子模块没有拉下来:
git submodule update --init --recursive
第一次克隆时建议使用:
git clone --recurse-submodules https://github.com/USERNAME/SOURCE_REPO.git
Actions 报 Permission denied (publickey)
按顺序检查:
- 源码仓是否存在名为
DEPLOY_KEY的 Actions Secret。 DEPLOY_KEY是否填入完整私钥。- Pages 仓库的 Deploy Key 是否使用对应公钥。
- Deploy Key 是否勾选
Allow write access。 DEPLOY_REPO是否使用 SSH 地址。
页面样式错乱或资源加载失败
优先检查 baseURL:
baseURL = 'https://USERNAME.github.io/'
如果是项目页,确认仓库名也在路径中:
baseURL = 'https://USERNAME.github.io/REPOSITORY_NAME/'
Actions 显示 No changes to publish
这不是错误,说明本次构建结果和 Pages 仓库中的文件一致,所以没有创建新提交。
CI 的 Hugo 和本地 Hugo 行为不一致
优先统一安装来源。比如本地使用 Hugo Extended,CI 也应该安装 Hugo Extended;本地使用包管理器,CI 也尽量使用相同渠道。不要只看 hugo version 能输出,还要确认主题依赖的功能在 CI 中可用。
Hugo + GitHub Pages 的关键不在命令数量,而在边界清晰:源码仓负责写作和构建,Pages 仓负责托管静态结果;本地和 CI 使用一致的 Hugo 能力;密钥只放在 GitHub Secrets,不进入代码仓库。

