前言
博客在本地已经搭建完成,也做好了一些优化和个性化配置,万事俱备,只欠东风,胜利就在前方。接下来我们开始着手将其部署到远程托管平台。
目前公认的稳定且免费的托管方案主要有两个: GitHub Pages 和 CloudFlare Pages,两个都行,但成年人不做选择,当然是两个都要了。
下面是一份针对部署到这两个平台的保姆级教程, 一步一步跟着做,保你通关。
二、准备工作
2.1 你需要的东西
| 项目 | 说明 |
|---|---|
| GitHub 账号 | 免费版即可 |
| Cloudflare 账号 | 免费版即可 |
| 本地 Hugo 站点 | 已经能正常 hugo server 预览 |
| 域名(可选) | 两个平台都支持自定义域名 |
三、第一步:创建仓库 A(源码仓库)
3.1 在 GitHub 创建仓库
- 打开 github.com/new
- Repository name:
blog-source(可以随便取,比如my-blog) - Description:
Hugo blog source code - Visibility:Private (这里选公开或私有都可以,没有强制要求)
- Initialize this repository with:勾选
Add a README file - 点击 Create repository
3.2 本地 Hugo 站点关联到仓库 A
打开终端,进入你的 Hugo 站点根目录(包含 hugo.toml 和 content/ 的文件夹):
# 初始化 git(如果还没初始化)
git init
# 添加远程仓库(把 你的用户名 替换成你的 GitHub 用户名)
git remote add origin https://github.com/你的用户名/blog-source.git
# 添加所有文件
git add .
# 提交
git commit -m "Initial commit: Hugo blog source"
# 推送到 main 分支
git push -u origin main如果提示
error: failed to push some refs,先执行git pull origin main --rebase再 push。
四、第二步:配置 Cloudflare Pages(自动构建)
4.1 授权 Cloudflare 访问你的私有 GitHub 仓库
- 登录 Cloudflare Dashboard
- 左侧菜单找到 Workers & Pages(或直接在首页搜索框搜 “Pages”)
- 点击 Create a project → 选择 Pages 标签
- 点击 Connect to Git
- 首次使用会弹出 GitHub 授权页面,点击 Authorize CloudflarePages
- 授权后,在仓库列表中找到你的私有仓库
blog-source,点击 Begin setup
4.2 配置构建设置
在 Set up builds and deployments 页面填写:
| 配置项 | 填写内容 |
|---|---|
| Project name | blog-source(会自动填充,可以改,只能小写字母、数字、连字符) |
| Production branch | main |
| Framework preset | 下拉选择 Hugo |
| Build command | hugo --minify |
| Build output directory | public |
如果下拉框里没有 Hugo,选择 None,然后手动填写上面两项。
4.3 设置环境变量(重要)
向下滚动到 Environment variables (advanced),点击 Add variable:
| 变量名 | 值 | 说明 |
|---|---|---|
HUGO_VERSION |
0.146.7 |
填写你本地 hugo version 看到的版本号,确保一致 |
HUGO_ENV |
production |
告诉 Hugo 这是生产环境 |
⚠️ 务必设置
HUGO_VERSION,否则 Cloudflare 可能用很旧的 Hugo 版本构建,导致失败。
点击 Save and Deploy。
4.4 等待首次构建
Cloudflare 会自动拉取仓库 A 的代码并构建。构建完成后会显示:
- Your site was deployed 和一个
*.pages.dev的预览链接 - 点击链接即可查看
4.5 (可选)绑定自定义域名
- 进入 Cloudflare Pages 项目 → Custom domains
- 点击 Set up a custom domain
- 输入你的域名(如
blog.example.com) - 按提示添加 DNS 记录(如果在 Cloudflare 托管域名,通常自动完成)
五、第三步:创建仓库 B(GitHub Pages 目标仓库)
5.1 创建公开仓库
- github.com/new
- Repository name:
你的用户名.github.io- 例如你的 GitHub 用户名是
zhangsan,就填zhangsan.github.io - ⚠️ 必须严格符合这个格式,才能使用
https://zhangsan.github.io这个默认域名 - 如果你不想用这个域名,可以用任意名称(如
blog-public),但访问地址会变成https://zhangsan.github.io/blog-public/
- 例如你的 GitHub 用户名是
- Visibility:Public ⚠️ GitHub Pages 免费版必须公开
- Initialize this repository with:勾选
Add a README file - 点击 Create repository
5.2 开启 GitHub Pages
- 进入仓库 B → 顶部菜单 Settings
- 左侧菜单找到 Pages(在 Code and automation 下面)
- Source 部分,选择 Deploy from a branch
- Branch:选择
main,文件夹选择/(root) - 点击 Save
此时页面会提示:Your site is ready to be published at https://你的用户名.github.io/
六、第四步:配置 GitHub Actions(仓库 A → 仓库 B)
这是核心步骤。我们需要在仓库 A 中创建一个工作流,每次推送时自动构建 Hugo,然后把 public/ 文件夹推送到仓库 B。
6.1 创建 Personal Access Token (PAT)
因为要从私有仓库 A 推送到仓库 B,需要一个有权限的 Token:
- 点击 GitHub 右上角头像 → Settings
- 左侧最下方 Developer settings → Personal access tokens → Tokens (classic)
- 点击 Generate new token (classic)
- Note:
Deploy to GitHub Pages repo - Expiration:选择 No expiration(或 90 天,到期后重新生成)
- Select scopes:勾选以下权限:
- ✅
repo(完整仓库控制) - ✅
workflow(如果需要更新 Actions)
- ✅
- 点击页面底部 Generate token
- ⚠️ 立即复制这个 token(页面关闭后无法再次查看)
6.2 将 Token 存入仓库 A 的 Secrets
- 进入你的私有仓库 A(
blog-source) - 顶部菜单 Settings → 左侧 Secrets and variables → Actions
- 点击 New repository secret
- Name:
GH_PAGES_TOKEN - Secret:粘贴刚才复制的 PAT
- 点击 Add secret
6.3 创建工作流文件
在本地 Hugo 站点根目录,创建文件夹和文件:
mkdir -p .github/workflows然后创建文件 .github/workflows/deploy.yml,内容如下:
name: Deploy to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch: # 允许手动触发
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
# 1. 检出源码
- name: Checkout source
uses: actions/checkout@v4
with:
submodules: recursive # 如果用了 git submodule 管理主题,必须加
fetch-depth: 0
# 2. 安装 Hugo Extended
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 'latest'
extended: true # 如果主题用了 SCSS/Sass,必须开 extended
# 3. 构建站点
- name: Build
run: hugo --minify
# 4. 推送到仓库 B(GitHub Pages)
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
personal_token: ${{ secrets.GH_PAGES_TOKEN }}
external_repository: 你的用户名/你的用户名.github.io # 修改这里!
publish_dir: ./public
publish_branch: main
commit_message: "Deploy from blog-source: ${{ github.event.head_commit.message }}"
cname: "" # 如果有自定义域名,填在这里,如 blog.example.com6.4 修改配置中的占位符
把上面 YAML 中的这两个地方改成你的:
-
external_repository: 你的用户名/你的用户名.github.io- 例如:
external_repository: zhangsan/zhangsan.github.io
- 例如:
-
如果用了自定义域名,把
cname: ""改成你的域名,如cname: blog.example.com
6.5 提交并推送
git add .github/workflows/deploy.yml
git commit -m "Add GitHub Actions for dual deployment"
git push origin main推送后,进入仓库 A → Actions 标签,应该能看到工作流正在运行。等待它变绿(✅)。
6.6 验证 GitHub Pages
- 进入仓库 B,确认
main分支有了新提交(来自 Actions 机器人) - 进入仓库 B → Settings → Pages
- 看到绿色提示:
Your site is live at https://你的用户名.github.io/ - 点击访问
七、第五步:开关控制(停用/启用某个平台)
7.1 停用 Cloudflare Pages
方法 A(推荐):暂停自动构建
- 登录 Cloudflare Dashboard
- 进入你的 Pages 项目
- 顶部菜单 Settings → Builds & deployments
- 找到 Pause deployments 按钮,点击暂停
- 需要恢复时,点击 Resume deployments
方法 B:取消 GitHub 关联
- Pages 项目 → Settings → Git
- 点击 Disconnect 断开与仓库 A 的关联
- 恢复时重新 Connect
7.2 停用 GitHub Pages
- 进入仓库 B → Settings → Pages
- Source 下拉框选择 None
- 点击 Save
- 站点会显示 404,表示已停用
- 恢复时重新选择
main分支
7.3 更优雅的开关:用 GitHub Actions 条件控制
如果你不想登录后台,也可以在仓库 A 的 Actions 中加开关变量:
- 仓库 A → Settings → Secrets and variables → Actions → Variables
- 新建变量:
- Name:
ENABLE_GITHUB_PAGES - Value:
true(启用)或false(停用)
- Name:
- 修改工作流文件,在 Deploy 步骤加
if条件:
- name: Deploy to GitHub Pages
if: ${{ vars.ENABLE_GITHUB_PAGES == 'true' }}
uses: peaceiris/actions-gh-pages@v4
with:
...这样你只需要改一个变量值就能控制是否推送到仓库 B,连代码都不用改。
八、第六步:日常写作流程
配置完成后,你每次写博客只需要做:
# 1. 本地写新文章
hugo new content posts/新文章.md
# 2. 编辑内容
# 用你喜欢的编辑器打开 content/posts/新文章.md
# 3. 本地预览
hugo server -D
# 4. 满意后提交
git add .
git commit -m "Add new post: 文章标题"
# 5. 推送(一键触发双平台部署)
git push origin main推送后:
- Cloudflare Pages:自动检测推送,约 30 秒~2 分钟完成构建
- GitHub Pages:Actions 自动运行,约 1~3 分钟完成构建并推送
九、注意事项与优化
9.1 构建版本一致性
Cloudflare 和 GitHub Actions 可能使用不同版本的 Hugo。建议:
- Cloudflare:已在环境变量中设置了
HUGO_VERSION - GitHub Actions:在
peaceiris/actions-hugo@v3中,hugo-version: 'latest'会自动拉最新版。如果你需要固定版本,改成具体版本号如hugo-version: '0.146.7'
9.2 关于 baseURL
Hugo 构建时 baseURL 只能有一个。两个平台的域名不同,解决方案:
方案 A(推荐):使用相对路径
修改 hugo.toml:
baseURL = '/'这样无论部署到哪个域名,链接都能正常工作。
方案 B:分别构建两次
在 Actions 中构建两次,分别指定不同 baseURL。但这会显著增加构建时间,不推荐。
9.3 主题作为子模块
如果你用 git submodule 管理主题(如 PaperMod),确保:
-
本地添加子模块:
bashgit submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod -
.github/workflows/deploy.yml中已包含submodules: recursive -
Cloudflare Pages 构建时也会自动拉取子模块(默认行为)
9.4 构建失败排查
如果 Actions 失败,点击失败的运行记录,查看日志:
| 常见错误 | 原因 | 解决 |
|---|---|---|
hugo: command not found |
Actions 没装 Hugo | 检查 peaceiris/actions-hugo 步骤 |
permission denied |
Token 权限不足 | 重新生成 PAT,勾选 repo |
remote: Repository not found |
仓库名写错 | 检查 external_repository |
| Cloudflare 构建失败 | Hugo 版本不兼容 | 检查 HUGO_VERSION 环境变量 |
9.5 安全性提醒
- PAT (Personal Access Token) 拥有你 GitHub 账户的仓库写入权限,不要泄露
- 如果 Token 泄露,立即去 GitHub Settings → Developer settings → Tokens 中 Delete 并重新生成
- 建议给 Token 设置过期时间(如 90 天),定期轮换
十、总结
你的方案完全可行,而且设计得很合理:
| 优点 | 说明 |
|---|---|
| 源码始终私有 | 仓库 A 是私有的,核心资产受保护 |
| Cloudflare 零配置 | 直接 Git 集成,无需 Actions,简单可靠 |
| GitHub Pages 可控 | 通过 Actions 推送,开关方便 |
| 双平台冗余 | 一个挂了另一个还能访问 |
唯一的"缺陷"是推送到仓库 A 时,Cloudflare 和 Actions 会并行构建,资源有点浪费,但功能完全正常。如果你介意,可以把 Cloudflare 也改成通过 Actions 部署(用 cloudflare/pages-action),但那样配置更复杂,你的当前方案已经是最优解。
跟着上面的步骤一步一步做,应该能顺利跑通。如果遇到具体报错,把错误日志贴出来我可以继续帮你排查。
评论
使用 GitHub 账号登录后参与讨论