前言

博客在本地已经搭建完成,也做好了一些优化和个性化配置,万事俱备,只欠东风,胜利就在前方。接下来我们开始着手将其部署到远程托管平台。

目前公认的稳定且免费的托管方案主要有两个: GitHub PagesCloudFlare Pages,两个都行,但成年人不做选择,当然是两个都要。不过实测下来,国内个别网络运营商访问 Github Pages 偶尔受限,相对来说 CloudFlare Pages 国内访问体验更好。如果只部署一个,建议选 CloudFlare

下面就是一份针对部署到这两个平台的保姆级教程, 一步一步跟着做,保你通关。


1、准备工作

1.1 你需要的东西

项目 说明
GitHub 账号 免费版即可
Cloudflare 账号 免费版即可
本地 Hugo 站点 已经能正常 hugo server 预览
域名(可选) 两个平台都支持自定义域名

2、第一步:创建仓库 A(源码仓库)

2.1 在 GitHub 创建仓库

  1. 打开 github.com/new
  2. Repository nameblog-source(可以随便取,比如 my-blog
  3. DescriptionHugo blog source code
  4. VisibilityPrivate (这里选公开或私有都可以,没有强制要求)
  5. Initialize this repository with勾选 Add a README file
  6. 点击 Create repository

2.2 本地 Hugo 站点关联到仓库 A

打开终端,进入你的 Hugo 站点根目录(包含 hugo.tomlcontent/ 的文件夹):

bash
# 初始化 git(如果还没初始化)
git init

# 添加远程仓库(把 你的用户名 替换成你的 GitHub 用户名)
git remote add origin git@github.com:你的用户名/blog-source.git
# 没有配置 ssh 密钥也可以使用下面 https 协议,但还是建议使用 ssh 地址。
# 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。


3、第二步:配置 Cloudflare Pages(自动构建)

3.1 授权 Cloudflare 访问你的私有 GitHub 仓库

  1. 登录 Cloudflare Dashboard
  2. 左侧菜单找到 Workers & Pages(或直接在首页搜索框搜 “Pages”)
  3. 点击 Create a project → 选择 Pages 标签
  4. 点击 Connect to Git
  5. 首次使用会弹出 GitHub 授权页面,点击 Authorize CloudflarePages
  6. 授权后,在仓库列表中找到你的私有仓库 blog-source,点击 Begin setup

3.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,然后手动填写上面两项。

3.3 设置环境变量(重要)

向下滚动到 Environment variables (advanced),点击 Add variable

变量名 说明
HUGO_VERSION 0.146.7 填写你本地 hugo version 看到的版本号,确保一致
HUGO_ENV production 告诉 Hugo 这是生产环境

⚠️ 务必设置 HUGO_VERSION,否则 Cloudflare 可能用很旧的 Hugo 版本构建,导致失败。

点击 Save and Deploy

3.4 等待首次构建

Cloudflare 会自动拉取仓库 A 的代码并构建。构建完成后会显示:

  • Your site was deployed 和一个 *.pages.dev 的预览链接
  • 点击链接即可查看

3.5 (可选)绑定自定义域名

  1. 进入 Cloudflare Pages 项目 → Custom domains
  2. 点击 Set up a custom domain
  3. 输入你的域名(如 blog.example.com
  4. 按提示添加 DNS 记录(如果在 Cloudflare 托管域名,通常自动完成)

4、第三步:创建仓库 B(GitHub Pages 目标仓库)

4.1 创建公开仓库

  1. github.com/new
  2. Repository name你的用户名.github.io
    • 例如你的 GitHub 用户名是 zhangsan,就填 zhangsan.github.io
    • ⚠️ 必须严格符合这个格式,才能使用 https://zhangsan.github.io 这个默认域名
    • 如果你不想用这个域名,可以用任意名称(如 blog-public),但访问地址会变成 https://zhangsan.github.io/blog-public/
  3. VisibilityPublic ⚠️ GitHub Pages 免费版必须公开
  4. Initialize this repository with勾选 Add a README file
  5. 点击 Create repository

4.2 开启 GitHub Pages

  1. 进入仓库 B → 顶部菜单 Settings
  2. 左侧菜单找到 Pages(在 Code and automation 下面)
  3. Source 部分,选择 Deploy from a branch
  4. Branch:选择 main,文件夹选择 /(root)
  5. 点击 Save

此时页面会提示:Your site is ready to be published at https://你的用户名.github.io/


5、第四步:配置 GitHub Actions(仓库 A → 仓库 B)

这是核心步骤。我们需要在仓库 A 中创建一个工作流,每次推送时自动构建 Hugo,然后把 public/ 文件夹推送到仓库 B。

5.1 创建 Personal Access Token (PAT)

因为要从私有仓库 A 推送到仓库 B,需要一个有权限的 Token:

  1. 点击 GitHub 右上角头像 → Settings
  2. 左侧最下方 Developer settingsPersonal access tokensTokens (classic)
  3. 点击 Generate new token (classic)
  4. NoteDeploy to GitHub Pages repo
  5. Expiration:选择 No expiration(或 90 天,到期后重新生成)
  6. Select scopes:勾选以下权限:
    • repo(完整仓库控制)
    • workflow(如果需要更新 Actions)
  7. 点击页面底部 Generate token
  8. ⚠️ 立即复制这个 token(页面关闭后无法再次查看)

5.2 将 Token 存入仓库 A 的 Secrets

  1. 进入你的私有仓库 Ablog-source
  2. 顶部菜单 Settings → 左侧 Secrets and variablesActions
  3. 点击 New repository secret
  4. NameGH_PAGES_TOKEN
  5. Secret:粘贴刚才复制的 PAT
  6. 点击 Add secret

5.3 创建工作流文件

在本地 Hugo 站点根目录,创建文件夹和文件:

bash
mkdir -p .github/workflows

然后创建文件 .github/workflows/deploy.yml,内容如下:

yaml
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: '0.161.1' # 或者用最新版 `latest`, 或者替换成你当前使用的版本
          extended: true  # 如果主题用了 SCSS/Sass,必须开 extended

      # 3. 构建站点
      - name: Build
        run: hugo --minify --baseURL 你的用户名.github.io

      # 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.com

5.4 修改配置中的占位符

把上面 YAML 中的这两个地方改成你的:

  1. --baseURL 你的用户名.github.io

    • 如果部署到两个平台,我们在 hugo.toml 内将 baseURL 设为 cloudflare 域名,这里给 github pages 另外指定对应的域名。
  2. external_repository: 你的用户名/你的用户名.github.io

    • 例如:external_repository: zhangsan/zhangsan.github.io
  3. 如果用了自定义域名,把 cname: "" 改成你的域名,如 cname: blog.example.com

5.5 提交并推送

bash
git add .github/workflows/deploy.yml
git commit -m "Add GitHub Actions for dual deployment"
git push origin main

推送后,进入仓库 A → Actions 标签,应该能看到工作流正在运行。等待它变绿(✅)。

5.6 验证 GitHub Pages

  1. 进入仓库 B,确认 main 分支有了新提交(来自 Actions 机器人)
  2. 进入仓库 B → Settings → Pages
  3. 看到绿色提示:Your site is live at https://你的用户名.github.io/
  4. 点击访问

6、第五步:开关控制(停用/启用某个平台)

6.1 停用 Cloudflare Pages

方法 A(推荐):暂停自动构建

  1. 登录 Cloudflare Dashboard
  2. 进入你的 Pages 项目
  3. 顶部菜单 SettingsBuilds & deployments
  4. 找到 Pause deployments 按钮,点击暂停
  5. 需要恢复时,点击 Resume deployments

方法 B:取消 GitHub 关联

  1. Pages 项目 → SettingsGit
  2. 点击 Disconnect 断开与仓库 A 的关联
  3. 恢复时重新 Connect

6.2 停用 GitHub Pages

  1. 进入仓库 B → Settings → Pages
  2. Source 下拉框选择 None
  3. 点击 Save
  4. 站点会显示 404,表示已停用
  5. 恢复时重新选择 main 分支

6.3 更优雅的开关:用 GitHub Actions 条件控制

如果你不想登录后台,也可以在仓库 A 的 Actions 中加开关变量:

  1. 仓库 A → Settings → Secrets and variables → Actions → Variables
  2. 新建变量:
    • Name: ENABLE_GITHUB_PAGES
    • Value: true(启用)或 false(停用)
  3. 修改工作流文件,在 Deploy 步骤加 if 条件:
yaml
      - name: Deploy to GitHub Pages
        if: ${{ vars.ENABLE_GITHUB_PAGES == 'true' }}
        uses: peaceiris/actions-gh-pages@v4
        with:
          ...

这样你只需要改一个变量值就能控制是否推送到仓库 B,连代码都不用改。


7、第六步:日常写作流程

配置完成后,你每次写博客只需要做:

bash
# 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 分钟完成构建并推送

8、注意事项与优化

8.1 构建版本一致性

Cloudflare 和 GitHub Actions 可能使用不同版本的 Hugo。建议:

  • Cloudflare:已在环境变量中设置了 HUGO_VERSION
  • GitHub Actions:在 peaceiris/actions-hugo@v3 中,hugo-version: 'latest' 会自动拉最新版。如果你需要固定版本,改成具体版本号如 hugo-version: '0.146.7'

8.2 关于 baseURL

Hugo 构建时 baseURL 只能有一个。两个平台的域名不同,解决方案:

推荐全局配置为 CloudFlare 域名, action 自动构建通过 --baseURL 参数传递 github Pages 域名。 修改 hugo.toml,改为 CloudFlare Pages 域名:

toml
baseURL = 'xxx.pages.dev'

这样无论部署到哪个域名,链接都能正常工作。

8.3 主题作为子模块

如果用 git submodule 管理主题(如 PaperMod),确保:

  1. 本地添加子模块:

    bash
    git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
  2. .github/workflows/deploy.yml 中已包含 submodules: recursive

  3. Cloudflare Pages 构建时也会自动拉取子模块(默认行为)

8.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 环境变量

8.5 安全性提醒

  • PAT (Personal Access Token) 拥有你 GitHub 账户的仓库写入权限,不要泄露
  • 如果 Token 泄露,立即去 GitHub Settings → Developer settings → Tokens 中 Delete 并重新生成
  • 建议给 Token 设置过期时间(如 90 天),定期轮换