Building and Deploying a Blog with Hugo and GitHub Pages
In today's fast-paced digital age, where information is just a Google or ChatGPT search away, setting yourself apart is more important than ever. Blogging is one of the most effective ways to showcase your knowledge, contribute to the community, and build your brand. Think of it as a dynamic extension of your resume, a portfolio that grows and evolves with you. It provides a platform to share ideas, tackle complex problems, and express your viewpoints while delivering immense value to your readers.
Prerequisites
- Git
- A GitHub account
- GitHub CLI
- PowerShell version 7 or higher (Do not use Windows PowerShell, per the Hugo website)
- Basic knowledge of Markdown
Install Hugo
Hugo is a static site generator built with Go. It's popular for its speed, flexibility, and ease of use. Hugo Extended is a variant of Hugo that supports additional features like Sass/SCSS compilation, image processing, and more. Hugo Extended is Hugo but with some extra capabilities to help manage more complex projects. For more information, see the Hugo website.
Install Hugo Extended using your operating system's package manager. While the following aren't the only ways to install Hugo, they're how I installed it on each operating system I use. For additional options, see the installation section of the Hugo website.
Windows
Install Hugo Extended using the Windows Package Manager.
1winget install Hugo.Hugo.Extended --source winget
macOS
Use the Homebrew package manager to install Hugo Extended.
1brew install hugo
Linux
Use the package manager for your distribution to install Hugo Extended. The following example uses the APT package manager to install Hugo Extended on Ubuntu.
1sudo apt install hugo
Create a Hugo site
Using PowerShell, navigate to the parent directory on your computer's file system where you want to
create your Hugo site. The examples in this article use the $HOME/Developer/git
directory as the
parent path.
1Set-Location -Path $HOME/Developer/git
Create a new Hugo site. The examples in this article use myhugosite
for the Hugo site name.
1hugo new site myhugosite
Navigate to the root directory of your newly created Hugo site.
1Set-Location -Path $HOME/Developer/git/myhugosite
Create a Git repository
Initialize the site's directory as a Git repository.
1git init
Add a .gitignore file
1$gitIgnore = @'
2.DS_Store
3.hugo_build.lock
4'@
5Set-Content -Path $HOME/Developer/git/myhugosite/.gitignore -Value $gitIgnore -Force
Add a theme
Adding a theme to a Hugo website can enhance its aesthetics and functionality. Hugo offers various methods for installing and using themes. This article uses Hugo modules to add a theme to the site. See your theme's documentation for guidance on adding a theme to a Hugo site.
Initialize a new Hugo module. This initialization creates a go.mod
file in the root of the site.
The go.mod
file tracks the dependencies of the site and the version of Go that the site uses. Hugo
and GitHub Actions use the version of Go when building the site.
1hugo mod init github.com/<github-username>/myhugosite
Remove the Go patch version from the go.mod
file. This modification is required because GitHub
Actions only supports Go specified in Major.Minor format. GitHub Actions builds and deploys the
site to GitHub pages and fails if the go.mod
file includes the patch version. For more information
about Semantic versioning, see semver.org.
1Get-Content -Path ./go.mod -OutVariable content
2$content -replace '([^\.]*\.[^\.]*)\..*', '$1' | Out-File -FilePath ./go.mod -Force
3Get-Content -Path ./go.mod
Add a theme to the Hugo site. This article uses the Relearn theme for Hugo.
1hugo mod get github.com/McShelby/hugo-theme-relearn
Configure Hugo to use the Relearn theme.
1Add-Content -Path hugo.toml -Value "theme = 'github.com/McShelby/hugo-theme-relearn'"
Add content
Create a new post. The following example uses the name my-first-article.md
for the new post. The
name of the post is the name of the file created in the content/posts
directory.
1hugo new content posts/my-first-article.md
Add content to the newly created my-first-article.md
post. You write the content for Hugo posts in
Markdown. Markdown is a lightweight markup language that you can use to add formatting elements to
plaintext text documents. Title and date are the only metadata elements specified in the following
example. See the documentation for your specific theme to determine the supported metadata.
1$post = @'
2---
3title: "My First Article"
4date: 2023-10-26T06:30:00-05:00
5---
6
7Insert lead paragraph here.
8
9> Block quote
10
11**bold**
12
13_italic_
14
15Unordered list
16
17- first
18- second
19- third
20
21Ordered list
22
231. first
241. second
251. third
26
27Inline code `Get-Help`.
28
29Cmdlet name `Get-Help`.
30
31Parameter name **ParameterName**.
32
33Parameter value `$true`.
34'@
35Set-Content -Path $HOME/Developer/git/myhugosite/content/posts/my-first-article.md -Value $post
Build the site locally
Start the Hugo server locally on your computer. Hugo serves the site locally so that you can view a live preview in your web browser. The Hugo server watches for changes to the site and automatically rebuilds it when changes are detected.
1hugo server
Consider starting hugo server
as a background job because otherwise, it ties up your PowerShell
prompt or session.
1Start-Job -Name hugo -ScriptBlock {hugo server} -WorkingDirectory $HOME/Developer/git/myhugosite
Visit the local site in your default web browser. Port 1313 is the default, but a different port is dynamically assigned if the default port is already in use.
1Start-Process http://localhost:1313/
The website should look similar to the following.
Stop the Hugo server by pressing CTRL+C in the PowerShell console or by stopping the PowerShell job, depending on how you started it.
1Get-Job | Stop-Job -PassThru | Remove-Job
Create a repository on GitHub
Add and commit the changes to your local Git repository.
1git add .
2git commit -m 'Initial commit'
Tip: To authenticate with GitHub using the GitHub CLI, run
gh auth login
.
Create a new repo on GitHub using the GitHub CLI and push your local clone to it. You can only use GitHub Pages with a public repo if you're using a free GitHub account. Private repos with GitHub Pages require a paid GitHub account.
1gh repo create myhugosite --public --push --source=. --description 'My hugo website'
Deploy the site to GitHub Pages
Enable GitHub Pages and set it to deploy via GitHub Actions. Use the GitHub CLI with the GitHub API to update the repo settings.
1gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/<github-username>/myhugosite/pages -F "source:branch=main" -F "source:path=/" -F "build_type=workflow"
Add the GitHub Actions workflow folder locally.
1New-Item -Path $HOME/Developer/git/myhugosite/.github/workflows -ItemType Directory -Force
Save the following GitHub Actions workflow to a file named Hugo.yaml
in the workflow folder. Run
hugo version
on your computer to determine what version of Hugo you're using and update the
version in the workflow. The following workflow is a modified version of the one found in the
Host on GitHub Pages section of the Hugo website.
1$workflow = @'
2# Sample workflow for building and deploying a Hugo site to GitHub Pages
3name: Deploy Hugo site to Pages
4
5on:
6 # Runs on pushes targeting the default branch
7 push:
8 branches:
9 - main
10
11 # Allows you to run this workflow manually from the Actions tab
12 workflow_dispatch:
13
14# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
15permissions:
16 contents: read
17 pages: write
18 id-token: write
19
20# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
21# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
22concurrency:
23 group: "pages"
24 cancel-in-progress: false
25
26# Default to bash
27defaults:
28 run:
29 shell: bash
30
31jobs:
32 # Build job
33 build:
34 runs-on: ubuntu-latest
35 env:
36 HUGO_VERSION: 0.119.0
37 steps:
38 - name: Install Hugo CLI
39 run: |
40 wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
41 && sudo dpkg -i ${{ runner.temp }}/hugo.deb
42 - name: Install Dart Sass
43 run: sudo snap install dart-sass
44 - name: Checkout
45 uses: actions/checkout@v3
46 with:
47 submodules: recursive
48 fetch-depth: 0
49 - name: Setup Pages
50 id: pages
51 uses: actions/configure-pages@v3
52 - name: Install Node.js dependencies
53 run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
54 - name: Build with Hugo
55 env:
56 # For maximum backward compatibility with Hugo modules
57 HUGO_ENVIRONMENT: production
58 HUGO_ENV: production
59 run: |
60 hugo \
61 --gc \
62 --minify \
63 --baseURL "${{ steps.pages.outputs.base_url }}/"
64 - name: Upload artifact
65 uses: actions/upload-pages-artifact@v1
66 with:
67 path: ./public
68
69 # Deployment job
70 deploy:
71 environment:
72 name: github-pages
73 url: ${{ steps.deployment.outputs.page_url }}
74 runs-on: ubuntu-latest
75 needs: build
76 steps:
77 - name: Deploy to GitHub Pages
78 id: deployment
79 uses: actions/deploy-pages@v2
80'@
81Set-Content -Path $HOME/Developer/git/myhugosite/.github/workflows/hugo.yaml -Value $workflow -Force
Add, commit, and push the changes. Pushing the changes to the main branch of your GitHub repo
triggers the GitHub Actions workflow. The GitHub Action is a build-and-deploy workflow that builds
and deploys the site to GitHub Pages. The GitHub Actions workflow automatically runs when you update
the main branch, and you can manually trigger it by running
gh workflow run 'Deploy Hugo site to Pages'
.
1git add .
2git commit -m 'Added GitHub Action workflow'
3git push
You can see the name of all your GitHub Actions workflows using the GitHub CLI.
1gh workflow list
Check the status of the GitHub Actions workflow. It may take a few minutes for it to complete.
1gh workflow view 'Deploy Hugo site to Pages'
Tip: The workflow failed if you didn't remove the Go patch version from the go.mod file, as described earlier in this article.
Once the GitHub Actions workflow completes successfully, visit the public website in your default web browser.
1Start-Process https://<github-username>.github.io/myhugosite/
The website should look identical to the local one you previewed and similar to the following.
Clean up resources
If the resources created in this article aren't needed, you can delete them by running the following commands.
Warning: The following commands perform non-recoverable destructive changes. If resources outside the scope of this article exist in the specified local directory or GitHub repo, these commands also delete them.
The following commands delete the site, GitHub repo, and local directory used in this article. I've placed a comment symbol before each command so you don't run them accidentally.
Tip: Deletion requires authorization with the delete_repo scope. To authorize, run
gh auth refresh -s delete_repo
.
1# Get-Job -Name hugo -ErrorAction SilentlyContinue | Stop-Job -PassThru | Remove-Job
2# Remove-Item -Path $HOME/Developer/git/myhugosite -Recurse -Force
3# gh repo delete myhugosite --yes
Summary
This article outlined how to set up a free blog using Hugo and GitHub Pages. It covered essential prerequisites, installation, and content creation. It also provided step-by-step instructions for local testing and online deployment through GitHub.
While outside the scope of this article, I recommend using a custom domain name for your blog in case you decide to move it somewhere else; you can maintain the existing URLs for your content. It's also easier to remember and share with others.