本地 hugo 能跑,到了 GitHub Actions 就翻车,是很多博客维护者的日常。 最常见的问题不是“不会写 workflow”,而是环境不一致、版本漂移、权限设置遗漏。

这篇给你一套能长期稳定运行的 Hugo 自动部署配置:最小必要权限、版本锁定、失败即报错、可快速排障。

一、先定规则:部署链路必须可预期

目标只有三个:

  • 每次 push 后自动构建并发布
  • 依赖版本固定,不吃“今天能跑明天挂”
  • 失败时日志有明确定位线索

二、推荐 workflow(可直接用)

在仓库创建 .github/workflows/deploy-hugo.yml

name: Deploy Hugo

on:
  push:
    branches: ["main"]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      HUGO_VERSION: "0.145.0"
      TZ: "Asia/Shanghai"
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: ${{ env.HUGO_VERSION }}
          extended: true

      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v5

      - name: Build
        run: hugo --minify --gc

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./public

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

三、为什么这份配置不容易炸

1) 锁定 Hugo 版本

  • 不要依赖 runner 默认版本
  • 主题更新后,版本差异经常导致模板渲染异常

2) 显式开启 Pages 权限

pages: writeid-token: write 缺一不可,否则 deploy 阶段会权限错误。

3) 打开并发互斥

连续 push 时,旧任务会自动取消,避免旧构建覆盖新内容。

4) 子模块递归拉取

如果主题在 submodule,不加 submodules: recursive 会直接构建失败。

四、你最可能遇到的 5 个报错

Error: Failed to create deployment

排查:

  • 仓库 Settings → Pages,Source 选择 GitHub Actions
  • workflow 里必须有 pages: writeid-token: write

hugo: command not found

排查:

  • actions-hugo 是否执行成功
  • hugo-version 是否填写并可用

module not found / 主题渲染报错

排查:

  • 是否有 submodules: recursive
  • 本地和 CI 的 Hugo 版本是否一致

No files were found with the provided path: ./public

排查:

  • hugo 是否真的输出到 public/
  • baseURL 或配置错误导致构建提前退出

页面部署成功但样式全丢

排查:

  • baseURL 是否与 Pages 域名匹配
  • 资源路径是否用绝对路径硬编码

五、建议加一个快速健康检查

在 Build 后追加:

      - name: Sanity check
        run: |
          test -f public/index.html
          echo "Build output looks good"

这个检查很土,但能防住“构建看起来成功,实际啥也没产出”的低级事故。

六、总结

想让 Hugo 自动部署稳定,重点不是“复杂配置”,而是:

  • 锁版本
  • 给对权限
  • 保证主题与依赖完整
  • 留下可读的失败日志

先把这四件事做对,你的博客 CI 会比大多数项目稳得多。