Build a Personal Website with Hugo

In this post, I will show you how to build a personal website with Hugo and configure the theme DoIt.

Install Hugo

In macOS, you can use Homebrew to install Hugo.

brew install hugo

Then add the theme DoIt as a submodule of the hugo project.

  1. Create a new hugo project:

    hugo new site my_website
    cd my_website
  2. Initialize your project directory as a git repository, and add the theme repository as a submodule of your website directory:

    git init
    git submodule add https://github.com/HEIGE-PCloud/DoIt.git themes/DoIt
  3. Initialize the project: git submodule update --init --recursive, and finish the installation.

  4. Update the submodule: git submodule update --remote --merge.

  5. Create your first post! hugo new posts/hello-world.md.

  6. Preview your website: hugo server --disableFastRender -D.

.
├── archetypes # markdown templates
├── assets # assets used to generate the website
├── content # website content, mainly posts
├── data # data files used to generate the website
├── public # static files generated by hugo, mainly publish this
├── resources # resources generated by hugo, not sure what it is
├── static # static files, e.g. images, thumbnails, etc.
├── themes # hugo themes
└── hugo.toml # configuration file
  • hugo.toml: The configuration of Hugo, including the configuration of the theme. See here for details.

  • content: Save the content of the website, such as posts.

    .
    └── content
       └── about
       |   └── index.md  // <- <https://example.com/about/>
       ├── posts
       |   ├── firstpost.md   // <- <https://example.com/posts/firstpost/>
       |   ├── happy
       |   |   └── ness.md  // <- <https://example.com/posts/happy/ness/>
       |   └── secondpost.md  // <- <https://example.com/posts/secondpost/>
       └── quote
          ├── first.md       // <- <https://example.com/quote/first/>
          └── second.md      // <- <https://example.com/quote/second/>
  • archetypes: Save the markdown templates of the posts, usually including the front matter of the posts.

  • static: Save the static files used in the posts, these files will be copied to the public folder when generating the website.

  • public: The static HTML, CSS, JS, etc. generated by the hugo command. This folder is mainly published on the server.

We can create two repositories on GitHub to deploy the website.

  • Repository 1: A repository used to host the source files of the website project, set the permission to Private. We will spend most of our time on this repository.
  • Repository 2: A repository used to host the static files generated by the website, set the permission to Public. The name of this repository should be {{your_github_username}}.github.io. For example, my GitHub username is fakephysicist, then the name of the repository I need to create is fakephysicist.github.io. In the settings of this repository, enable GitHub Pages, set Branch to main, and set the static file location to /(root). We will directly push the contents of the public folder generated by the hugo command to the / directory of the main branch.

Create these two repositories on GitHub, and then follow the steps below to deploy the website.

  1. In the my_website directory, execute git submodule update --init --recursive to update the submodules to the latest state.

  2. In hugo.toml, set baseurl = https://fakephysicist.github.io/.

  3. Set the fakephysicist.github.io repository as a submodule and set it in the public folder.

    git submodule add -f -b main <https://github.com/fakephysicist/fakephysicist.github.io.git> public
  4. Generate the website, and push the generated website to repository 2.

    hugo
    cd public
    git add .
    git commit -m "Build website"
    git push origin main
    cd ..
  5. Add, commit and push repository 1.

    git add .
    git commit -m "Publish website"
    git push -u origin master

Next time you want to update the website, just execute the following script deploy.sh.

#!/bin/bash
set -e

# Optional: Custom commit message
commit_msg=${1:-"Update site"}

# Step 1: Ensure you're in the root of the Git repo
if [ ! -d ".git" ]; then
    echo "❌ You must run this script from the root of the Git repository."
    exit 1
fi

# Step 2: Update the submodule if it's not initialized
if [ ! -d "public/.git" ]; then
    echo "➡️ Initializing submodule..."
    git submodule update --init --recursive
fi

# Step 3: Pull latest from GitHub Pages branch (optional, but safe)
echo "🔄 Updating submodule content..."
cd public
git checkout main
git pull origin main
cd ..

# Step 4: Generate the site into public/
echo "🏗 Running Hugo to build the site..."
hugo

# Step 5: Commit & push changes in public submodule
cd public
git add .
if git diff --cached --quiet; then
    echo "✅ No changes in public to commit."
else
    git commit -m "$commit_msg"
    git push origin main
    echo "✅ Pushed updates to GitHub Pages repo."
fi
cd ..

# Step 6: Commit & push changes in main repo (content, config, etc.)
git add .
if git diff --cached --quiet; then
    echo "✅ No changes in main repo to commit."
else
    git commit -m "$commit_msg"
    git push origin main
    echo "✅ Pushed changes to main repository."
fi

echo "🚀 Deployment complete!"

If this script is saved in the root directory of the project, you can run it with the following command:

bash deploy.sh "<your commit message>"
date +'%Y-%m-%dT%H:%M:%S%z' | sed 's/\(..\)$/:\1/'

One can use the above command to get the current timestamp in the format of 2024-08-04T14:20:29-07:00.

This timestamp can be used in the front matter of the posts.

date: 2021-01-01T02:43:06-05:00
lastmod: 2024-08-04T14:20:29-07:00