Skip to main content

Free Static Blog Deployment with GitHub Actions

Auto-build and deploy Hugo blog to GitHub Pages with GitHub Actions

Introduction

Building a static blog with Hugo and deploying it to the public web — no server required, update anytime, anywhere as long as you have internet access.

The core idea: create a private repo on GitHub for source code, use GitHub Actions to auto-build the static site, and push the public folder to a public repo. Anyone can view your site once the static files are on a public server. This guide focuses on the deployment workflow rather than how to build a static site — there are many tools for that (or you can even write plain .html).

Reference Video: B站 Tutorial

Reference Article: Deploy Hugo Blog with GitHub Actions


1. Prerequisites

  • Git installed (for pushing to GitHub)
  • A Hugo static site project (with baseURL set to your public repo URL or custom domain)

2. Deployment Steps

2.1 Create a Private Repo

Name it hugo-site (or any name you prefer).

git add .
git commit -m "Initial commit"
git push

Push all source code to the private repo.

2.2 Create a Public Repo

Name it hugo-public.

2.3 Create a Token

Profile → SettingsDeveloper SettingsPersonal access tokensTokens (classic)Generate new token (classic)

  • Note: hugo-auto-deploy
  • Scope: repo
  • Click Generate token

⚠️ Save the token string! It will only be shown once.

2.4 Add Token Secret to Private Repo

Go to your private repo hugo-siteSettingsSecrets and variablesActionsNew repository secret

  • Name: HUGO_TOKEN
  • Value: Paste the token

Summary of setup:

Item Description
Private repo hugo-site (source code)
Public repo hugo-public (built static files)
Token secret HUGO_TOKEN (write access to public repo)

Default site URL: https://{your-username}.github.io/hugo-public/


3. Configure Actions

The goal: every time you push to the private repo, GitHub Actions builds the site and pushes the public folder to the public repo.

Create .github/workflows/hugo_deploy.yaml in your Hugo project:

name: deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-24.04
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: "0.139.2"
          extended: true

      - name: Build Web
        run: hugo -D

      - name: Deploy Web
        uses: peaceiris/actions-gh-pages@v4
        with:
          PERSONAL_TOKEN: ${{ secrets.HUGO_TOKEN }}
          EXTERNAL_REPOSITORY: your-username/your-public-repo
          PUBLISH_BRANCH: main
          PUBLISH_DIR: ./public
          commit_message: auto deploy

Modify the last two lines:

  • EXTERNAL_REPOSITORY: your username and public repo name
  • secrets. variable name: match what you set (e.g., HUGO_TOKEN)

Then push to the private repo.

Verify Success

Method 1: Check the Actions tab — a green checkmark means success.

Method 2: Refresh the public repo to see if files have been pushed.


4. Enable GitHub Pages

In your public repo hugo-publicSettingsPages:

  • Source: Deploy from a branch
  • Branch: main/ (root)

Once set, you’ll see:

Your site live at https://{your-username}.github.io/hugo-public/

Open that URL — your blog is live!


5. Custom Domain (Optional)

To use your own domain:

  1. In Pages settings, enter your domain under Custom domainSave
  2. Add DNS records at your domain provider:
Type Name Value
A @ 185.199.108.153
A @ 185.199.109.153
A @ 185.199.110.153
A @ 185.199.111.153
CNAME www your-username.github.io

GitHub will automatically provision an HTTPS certificate. It may take a few minutes.


6. Summary & Tips

  1. Domain setting: Make sure baseURL in your Hugo config matches your public repo URL or custom domain
  2. Save your token: It’s only shown once. If lost, you can regenerate it
  3. Action updates: YAML configurations may change with official updates — keep an eye on GitHub announcements
  4. Branch name: Ensure the branches field in your YAML matches your repo’s default branch (main or master)