Looking back at my first post in Bahasa Indonesia, I said that I was using Hugo to build this blog. So, in this post, I’ll show you how to make your own!


Below are the main goals of this post:

  • Installing Hugo
  • Creating a Site with Hugo
  • Deploying the site using GitHub pages


There are some prerequisites needed to accomplish these goals:

  • A GitHub account
  • Familiarity with CLI commands and basic Git workflow
  • Git Bash for Windows users

If all set, then let’s get started

Installing Hugo

First thing first, we’ll need the Hugo executable binary, which you can grab it at https://github.com/gohugoio/hugo/releases. Pick your Hugo version according to what OS you’re on. There is also the extended version, which you should use if you’re building your own theme or picking a theme that uses Sass/SCSS.

I will assume that you have downloaded the binary and extracted it somewhere on your system.

$ ls -l
total 47488
-rw-r--r-- 1 Fahmi FJ 197121    11357 Mar 22 00:17 LICENSE
-rw-r--r-- 1 Fahmi FJ 197121    12345 Mar 22 00:17 README.md
-rwxr-xr-x 1 Fahmi FJ 197121 48599040 Mar 22 01:04 hugo.exe

Let’s test it on terminal by typing:

$ hugo.exe version
hugo v0.82.0-9D960784+extended windows/amd64 BuildDate=2021-03-21T17:28:04Z VendorInfo=gohugoio

At this time, Hugo’s binary is not available in a system-wide (it’s not accessible outside the current directory). Therefore, we’ll make it accessible system-wide by adding the binary location to what is known as PATH variable.

System-wide in Windows

For Windows users, let’s create a folder called bin in C:/ .

C:\>mkdir bin

Once the folder is created, move your Hugo binary into it.

C:\>dir bin
 Volume in drive C is Windows
 Volume Serial Number is AC06-7D93

 Directory of C:\bin

13/06/2021  08:07    <DIR>          .
13/06/2021  08:07    <DIR>          ..
22/03/2021  01:04        48.599.040 hugo.exe
               1 File(s)     48.599.040 bytes
               2 Dir(s)  57.909.837.824 bytes free

After that, hit Win + R on your keyboard and type:

rundll32.exe sysdm.cpl,EditEnvironmentVariables

You should see a window titled “Environment Variables”, and we’re going to edit the Path variable there.


On the edit window, add a new path and type C:\bin.


After that, just hit all the OK button.

Re-open your Windows terminal and run hugo version. If it returns the same output as previous one, then go to the next section.

System-wide in Linux

I know those who use Linux probably already know how to 😁.

For Linux users, let’s create a folder called bin under /home/username/.local/[here].

$ mkdir -p ~/.local/bin

Then move your Hugo binary into the newly created bin folder.

$ mv /previous/path/of/hugo ~/.local/bin/hugo

Next, open your .bashrc or .zshrc file which is located at /home/username/.(zsh|bash)rc with your favorite text editor such as vim, and then simply add these lines at the top of your .bashrc/.zshrc file.


Re-open your terminal and run hugo version from any directory and see if it’s returns the version.

Creating First Site

We can create a site in anywhere by issuing the command below, but I recommend you to create a site in a specific folder such as workspace or something like /workspace/your.blog.domain.com.

$ hugo new site [site-name]

For now, let’s call our new site my-blog.

$ hugo new site my-blog
Congratulations! Your new Hugo site is created in C:\Users\fahmi\Desktop\test\my-blog.

Just a few more steps and you're ready to go:

1. Download a theme into the same-named folder.
   Choose a theme from https://themes.gohugo.io/ or
   create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
   with "hugo new <SECTIONNAME>\<FILENAME>.<FORMAT>".
3. Start the built-in live server via "hugo server".

Visit https://gohugo.io/ for quickstart guide and full documentation.

We see that Hugo creates a new folder called my-blog at C:\Users\fahmi\Desktop\test\my-blog, and this my-blog has the following directory structure:

├── archetypes
│   └── default.md
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes

We can host that site locally by typing hugo server within my-blog directory. By default, the site is hosted at http://localhost:1313/ , but it’ll be empty because we haven’t added any content yet.

$ cd my-blog
$ hugo server

Using a Theme

You can choose any themes available on GitHub or at https://themes.gohugo.io/. But since my blog uses a theme called PaperMod, we’ll be using that too here.

For PaperMod, it prefers YAML instead of TOML, let’s delete the previous my-blog and recreate it with the following command:

$ rm my-blog -rf # becareful with this or just delete it from explorer
$ hugo new site my-blog -f yml

We’ll add the PaperMod theme by cloning it into the my-blog/themes/ directory/

$ git clone https://github.com/adityatelange/hugo-PaperMod themes/PaperMod --depth=1

Then replace/overwrite our config.yml with this one, and modify the value of baseUrl and theme to these:

baseURL: ""
theme: PaperMod

Let’s see how it looks like by visiting http://localhost:1313 on the browser after we run this command.

$ hugo server

Creating First Post

We can create a new post by issuing the following command:

$ hugo new post/new-post.md

You can edit new-post.md after that, the file should be under my-blog/content/post/[here].

$ ls -l my-blog/content/post/
total 1
-rw-r--r-- 1 Fahmi FJ 197121 70 Jun 13 09:34 my-post.md

To see your post in the site, change the value draft from true to false:

title: "My Post"
date: 2021-06-13T09:34:43+07:00
draft: false

My first post

It should be on your site now.

Deploying The Site on GitHub

From here, one thing you need to know is that when you run hugo server, Hugo generates all the site resources (html, images, etc.) and serves them directly from memory. But, if you just run hugo, Hugo generates all the site resources under public folder (my-blog/public/[here]).

The files in this public folder are the files that we are going to host on GitHub. We can simply upload all the files in the public folder into a GitHub repository.

But, before that, you have to change your site’s base URL in config.yml to:

baseURL: "https://[your_user_name].github.io/my-blog/"

For example, my username is fahmifj , so my config would be:

baseURL: "https://fahmifj.github.io/my-blog/"

Once you done with the config, type hugo within the site root directory and Hugo will re-generate all the resources we just deleted.

$ hugo
Start building sites …

                   | EN | FR | FA
  Pages            | 14 | 10 | 10
  Paginator pages  |  0 |  0 |  0
  Non-page files   |  0 |  0 |  0
  Static files     |  0 |  0 |  0
  Processed images |  0 |  0 |  0
  Aliases          |  3 |  0 |  1
  Sitemaps         |  2 |  1 |  1
  Cleaned          |  0 |  0 |  0

Total in 147 ms

Now, let’s navigate to Github and create a new repository called my-blog. Once the repo is created, click on Upload an existing file.


Then simply drag and drop all the files from the my-blog/public folder there.


Once all the files are uploaded, commit the changes. I’ll just leave the default commit message.


After that, let’s head to the repository settings and find the Github Pages menu: https://github.com/your-username/my-blog/settings/pages.

Since we’ll host this whole repository using GitHub pages, so under the source section, select the root directory of main branch, and then click on the Save button.


Once you done with that, navigate to https://yourusername.github.io/my-blog, and you should see your site there.


If you don’t see it or the page returns a 404 error, then just wait for a few minutes more.

Deployment Script

Finally, we’re going to (semi) automate the deployment process using a bash script.

Let’s go back to the directory of my-blog and then initialize public folder as a git repository. We’ll also add the public folder as a submodule.

$ cd public
$ git init
$ git remote add origin https://github.com/your-username/my-blog.git

Now let’s create a deployment script at the site root directory and name it as deploy.sh.


echo -e "\033[0;32mDeploying blog to GitHub...\033[0m"

# Clean public folder
hugo --cleanDestinationDir

# Go to to public folder
cd public/

# Add untracked files, hide output
git add -A > /dev/null

# Generate a fixed commit message with date and time
msg="[`date "+%R %d-%h-%Y"]` Site update"
# Check for additional commit message
read -p "Add commit message: " add_msg
if [ "$add_msg" != "" ]
	msg="$msg - $add_msg"

git commit -m "$msg"

# Deploy
git push -u origin main

# Go back to the root directory
cd ../

You can run the script on Windows within Git Bash or WSL.

Let’s create another post to test the deployment script.

$ hugo new post/second-post.md
$ echo 'This is second post' >> content/post/second-post.md

Don’t forget to change the value of draft from true to false, here is a small trick with sed.

$ sed -i 's/draft: false/draft: true/g' content/post/second-post.md

Now we can run the script, the output should look something like this:

$ ./deploy.sh
Deploying blog to GitHub...
Start building sites …

                   | EN | FR | FA
  Pages            | 15 | 10 | 10
  Paginator pages  |  0 |  0 |  0
  Non-page files   |  0 |  0 |  0
  Static files     |  0 |  0 |  0
  Processed images |  0 |  0 |  0
  Aliases          |  3 |  0 |  1
  Sitemaps         |  2 |  1 |  1
  Cleaned          |  0 |  0 |  0

Total in 155 ms
Add commit message:
[main af4c483] [11:00 13-Jun-2021] Site update
 9 files changed, 459 insertions(+), 8 deletions(-)
 create mode 100644 post/second-post/index.html
Enumerating objects: 27, done.
Counting objects: 100% (27/27), done.
Delta compression using up to 8 threads
Compressing objects: 100% (13/13), done.
Writing objects: 100% (15/15), 3.54 KiB | 1.77 MiB/s, done.
Total 15 (delta 9), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (9/9), completed with 7 local objects.
To https://github.com/fahmifj/my-blog.git
   f7141a3..af4c483  main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

It should be updated if we check our repo.


That’s it!

This is how I deployed my blog at the first time. However, this is an inefficient method because it wastes your bandwidth. Therefore, in the next post, let’s employ GitHub action 😼.