I tried creating my first website using HUGO . Here, I’ll leave a record of the steps as a memorandum.

Static Site Generators

FeaturePlain HTMLJekyllHugo
Language BaseHTML/CSS/JSRubyGo
SetupNoneMediumSomewhat Hard
GitHub Pages◎ (Direct)◎ (Official)○ (Push after build)
Build SpeedSlowUltra-fast
MultilingualManualPartially◎ (Standard)
Templates/ThemesManualManyVery Many
Best ForSmall/FreeMedium/BlogMedium-Large/Multi-lang

This time, I decided to use Hugo. The key points for this choice were:

  • For sites where pages will increase, like a blog or research log, Jekyll or Hugo are suitable.
  • I want to support both Japanese and English → Hugo is a good fit.
  • Auto-deployment with GitHub Actions is easy with Hugo.

Environment Setup

Installing Hugo

For macOS:

brew install hugo

If you can confirm the version with hugo version, you’re good to go.

Creating a New Site

In your desired location, enter the following command (replace my-website with any name you like):

hugo new site my-website
cd my-website

Selecting a Website Theme

ThemeFeatures
hugo-coderSimple & lightweight. Suitable for profile sites.
PaperModEasy to read & blog format. Popular for academic use.
Academic (Wowchemy)Best for researchers. Supports publication lists and project intros. A bit heavy.

This time, I chose PaperMod.
After moving to the website directory created above, I cloned the theme with the following commands:

git init
git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

This completes the environment setup.

How to Create Web Pages with Hugo

Creating web page content is basically done by editing Markdown files. Based on the created md files, Hugo outputs the static site as HTML.

File Structure

.
├── .github/
│   └── workflows/
│       └── deploy.yml  # Automation by means of Github Actions
├── archetypes/
│   └── default.md  # Template for markdown files
├── assets/
├── content/  # Create site content here
│   ├── en/  # For English
│   │   │── _index.md  # Description for the section's top page
│   │   └── blog/
│   │       │── _index.md  # Description for the section's top page
│   │       └── 01-first-post.md  # Content for the page
│   └── ja/  # For Japanese
│       ├── _index.md
│       └── blog/
│           │── _index.md  # Description for the section's top page
│           └── 01-first-post.md  # Content for the page
├── data/
├── hugo.toml  # Site configuration
├── i18n/
├── layouts/
├── public/   # Generated static site by Hugo (output)
├── static/
└── themes/
    └── PaperMod/
        ├── ... (Theme files)

Configuration of archetypes/default.md

By setting this up, you can create a template for your markdown files generated by hugo new <file-name>.md.

---
date: '{{ .Date }}'
draft: true
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
type: '{{ .Section }}'
tags: []
categories: []
---

Configuration of hugo.toml

This is the central file for managing the entire Hugo site’s configuration. It determines the site’s appearance, functionality, and structure.

baseURL = 'https://riichisugai.github.io/'  # Public URL of the site
languageCode = 'en-us'  # Main language of the site
theme = "PaperMod"  # Theme design to use
title = 'Riichi Sugai'  # Title of the site

relativeURLs = false  # Disable relative URLs
canonifyURLs = true   # Use absolute URLs

# Explicitly set the default language
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true

# Multilingual support settings
[languages]
  # English page settings
  [languages.en]
    weight = 1
    languageName = "English"
    contentDir = "content/en"  # Directory where the site's content is located
    mainSections = ["blog"]
    
    # English page header menu settings
    [[languages.en.menu.main]]
      identifier = "blog"
      name = "Blog"   # Header name displayed on the site
      url = "/blog/"  # Site directory
      weight = 1      # Display order priority
  
  # Japanese page settings
  [languages.ja]
    weight = 2
    languageName = "日本語"
    contentDir = "content/ja"
    mainSections = ["blog"]
    
    # Japanese page header menu settings
    [[languages.ja.menu.main]]
      identifier = "blog"
      name = "Blog"
      url = "/blog/"
      weight = 1

[params]
  # Display a copy button in code blocks on the page
  ShowCodeCopyButtons = true
  author = "Riichi Sugai"

  # Settings for displaying recent posts on the top page
  [params.homeInfoParams]
    ShowRecentPosts = true # Show recent posts
    RecentPostsCount = 3   # Set number of posts to display to 3

  # Validate Top page
  [outputs]
    home = ["HTML", "RSS", "JSON"]

Creating the Top Page

Create a top page under content/en/ or content/ja..

hugo new content/en/_index.md
hugo new content/ja/_index.md

_index.md functions as the top page and should be prepared for each section.

Note Always use the hugo new command when creating markdown files. Not doing so can cause bugs in the web page preference and display.

Creating Content

As an example of content to create, let’s make a directory blog. Create a directory named blog at the same level as the top page, and move into that directory.

  1. Create a top page _index.md in /content/en/blog/
hugo new /content/en/blog/_index.md

Then create a file with the following content.

---
date: '2025-11-01T02:14:44+09:00'
draft: true
title: 'Blog'
type: 'blog'
tags: []
categories: []
---

Here, draft: false indicates the page is published and will be displayed on the web. On the other hand, draft: true means it’s a draft and won’t be displayed.

  1. Create content 01-first-post.md in /content/en/blog
hugo new /content/en/blog/01-first-post.md

And at the beginning of the file, add the following:

---
date: '2025-11-01T02:14:44+09:00'
draft: true
title: 'Blog'
type: 'blog'
tags: []
categories: []
---

By having the same header as the top page, each piece of content will be displayed in a card format on the top page. The content itself should follow this header. The writing method follows the usual markdown syntax.

Previewing the Site

To preview the site locally, run the following command in the site’s root directory:

hugo server -D

Then, open http://localhost:1313/ in your web browser to view the site. The -D option includes pages marked as draft: true in the output. You can stop the server by pressing Ctrl + C in the terminal.

Publishing on Github.io

To publish the web page, we will use GitHub Pages, a free hosting service provided by GitHub for static sites.

  1. First, create a public GitHub repository named <username>.github.io.
  2. From [Settings], set the Default branch to gh-pages (optional).
  3. In [Settings] > [Pages], set Source to Deploy from a branch, and specify the branch set in step 2.

The web site will be pushed to the gh-pages branch of this repository to publish it in the following steps.

  1. Build the Hugo site on GitHub’s server (execute the hugo command).
  2. cd public
  3. git init
  4. git remote add origin https://github.com/<username>/<username>.github.io.git
  5. git add .
  6. git commit -m "Deploy website"
  7. git push -f origin gh-pages
  8. Open your browser and navigate to https://<username>.github.io/ to see your published site.

Automating Deployment with Github Actions

To automate the deployment process, we can use GitHub Actions to set up a workflow that automatically builds and deploys the site whenever changes are pushed to the main branch of the source repository.

  1. Build the site on GitHub’s server (execute the hugo command).
  2. Extract the contents of the generated public directory.
  3. Push to the gh-pages branch of the public repository (<username>.github.io).

Preparation

  1. Source code repository: riichisugai/hugo-source

    • This repository contains the source code of the Hugo site.
  2. Public repository: riichisugai/riichisugai.github.io

    • This repository is used to publish the generated static site.
  3. Personal Access Token (PAT):

    • A token with write access (repo scope) to the public repository.
    • This acts as a password for GitHub Actions to push to riichisugai.github.io.
  4. GitHub Secret:

    • A place to securely store the PAT in the source code repository (hugo-source).
    • This will be registered as GH_PAT.

Steps to Create the Workflow

Step 1: Create the Workflow File

  1. Navigate to [Settings] > [Developer settings] > [Personal access tokens] > [Tokens (classic)] in GitHub.
  2. Click [Generate new token]
  3. Fill in the required fields:
    • Note: Hugo Deploy Token
    • Expiration: Choose as needed
    • Scopes: Select repo
  4. Click [Generate token] and copy the generated token.

Step 2: Register the Token as a GitHub Secret

  1. Go to the riichisugai/hugo-source repository.
  2. Navigate to [Settings] > [Secrets and variables] > [Actions] > [New repository secret].
  3. Set the name to GH_PAT and paste the copied token into the value field.
  4. Click [Add secret].

Step 3: Create the Workflow YAML File

  1. In the riichisugai/hugo-source repository, create a directory .github/workflows/ if it doesn’t exist.
  2. Inside this directory, create a file named deploy.yml with the following content:
name: Deploy Hugo site to GitHub Pages

on:
  push:
    branches:
      - main  # Trigger on pushes to the main branch

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source code
        uses: actions/checkout@v4
        with:
          submodules: true  # Ensure submodules (themes) are checked out
          fetch-depth: 0    # Fetch all history for all branches and tags
          persist-credentials: false

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: 'latest'

      - name: Generate commit message
        id: commitmsg
        run: |
          # Obtain the list of changed files in the 'content' directory
          CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD content 2>/dev/null)
          if [ -z "$CHANGED_FILES" ]; then
            echo "MESSAGE=Deploy site on $(date '+%Y-%m-%d %H:%M:%S')" >> $GITHUB_ENV
          else
            TITLES=$(echo "$CHANGED_FILES" \
                      | sed 's|content/||g' \
                      | sed 's|/_index.md||g' \
                      | sed 's|.md||g' \
                      | tr '\n' ', ')
            echo "MESSAGE=Update: ${TITLES} ($(date '+%Y-%m-%d %H:%M:%S'))" >> $GITHUB_ENV
          fi
          echo "Commit message: $MESSAGE"

      - name: Build Hugo site
        run: hugo --cleanDestinationDir --minify

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          personal_token: ${{ secrets.GH_PAT }}
          external_repository: riichisugai/riichisugai.github.io
          publish_dir: ./public
          punlish_branch: gh-pages
          commit_message: ${{ env.MESSAGE }}
          user_name: 'github-actions[bot]'
          user_email: 'github-actions[bot]@users.noreply.github.com'
  • Checkout source; with: submodules: true must need to be included to properly fetch the theme which is a submodule.

Step 4: Execute and Verify the Workflow

  1. Push the created deploy.yml file to the main branch of the hugo-source repository.
  2. Go to the Actions tab of the hugo-source repository to see the workflow execution.
  3. If the workflow completes successfully with a green check mark, the auto-deployment is successful.
  4. Verify that the site is displayed correctly.

That’s the procedure for creating a website with Hugo and publishing it using Github Pages. Enjoy building your site!