Building a Free Blog with Markdown Using GitHub Pages and Hugo

A step-by-step guide to creating a free blog with Hugo and GitHub Pages, covering installation, themes, Google Analytics, and sitemap setup.

Introduction

With GitHub Pages, you can publish websites for free. I learned that combining it with a static site generator (Hugo in this case) makes it easy to create a blog, so I decided to try it. This is a summary of that process.

What is Hugo?

When building a blog, Content Management Systems (CMS) like WordPress are commonly used for their ease of content creation and editing. However, using a CMS requires installing and configuring the CMS itself and setting up a database, which can be complex. For small blogs, creating a static site with HTML files can be more cost-effective. That said, manually creating HTML files is tedious. This is where static site generators come in, and Hugo is one of them.

Hugo is a static site generator built with Go. With Hugo, you can create a blog consisting of static HTML and CSS files without needing a database. Content is written in Markdown format, and building generates static HTML files.

hugo-logo.png

Advantages of Hugo:

  • Fast build and rendering
  • No database required, making management simple

Creating a Site with Hugo

Installing Hugo

# With Homebrew (macOS)
brew install hugo

For other installation methods, see Install Hugo.

Creating a Site

hugo new site test # 'test' can be any name
cd test
hugo # This command generates the site

Previewing on Local Server

hugo server

Preview at http://localhost:1313.

Directory Structure

.
├── archetypes # Files processed by Hugo Pipes
├── config.toml # Hugo configuration file
├── content # Article files go here
├── data # Data files referenced across all pages
├── layouts # For customizing theme files or adding layout partials
├── public # Generated HTML code (this gets published)
├── static # Static files for the site
└── themes # Theme files

Using a Theme

Choose a theme from Hugo Themes and clone it into the themes folder.

cd themes
git clone <theme-repo-url>

Add the following line to config.toml:

theme = "chosen-theme-name"

temple.png

Creating Blog Posts

cd test
hugo new post/new-post.md

Contents of new-post.md:

---
title: "Title"
date: 2020-08-16T15:17:23+09:00
draft: false # Set to true to hide the post
tags: ["python", "ros"]
---
Write your article in Markdown here
  • Run the hugo command to generate static files under the public directory:
cd test
hugo

GitHub Pages

Creating a GitHub Repository

Click the “+” icon in the top right of GitHub and select “New repository.” Name the repository “username.github.io.” The published URL will be https://username.github.io.

github.png

Upload the public Folder

Since GitHub Pages only serves HTML files from the repository root, upload the public folder from your Hugo project to the “username.github.io” repository. Manage the Hugo project (test folder) itself in a separate repository or branch.

Additional Tips

Running Hugo

Preview locally:

hugo server

Preview including drafts:

hugo server -D

Enabling LaTeX Math Formulas

Create /layouts/partials/add_mathjax.html:

<script>
    MathJax = {
        tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']]
        }
    };
</script>

<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>

Add to /layouts/partials/site-header.html:

{{ partial "add_mathjax.html" . }}

Google Analytics

Add the following to config.toml:

googleAnalytics = "Measurement-ID"

Since the built-in template for Google Analytics integration is outdated, edit layouts/partials/head.html:

- {{ template "_internal/google_analytics_async.html" . }}
+ {{- partial "analytics" . -}}

Create layouts/partials/analytics.html:

{{ if not .Site.IsServer }}
{{ with .Site.GoogleAnalytics }}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
<script>
   window.dataLayer = window.dataLayer || [];
   function gtag(){dataLayer.push(arguments);}
   gtag('js', new Date());
   gtag('config', '{{ . }}');
</script>
{{ end }}
{{ end }}

Creating a Sitemap

Create layouts/sitemap.xml:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{{ range .Data.Pages }}{{ if .IsPage }}
<url>
  <loc>{{ .Permalink }}</loc>
  {{ if not .Lastmod.IsZero }}
  <lastmod>{{ safeHTML ( .Lastmod.Format "2006-01-02T15:04:05-07:00" ) }}</lastmod>
  <changefreq>weekly</changefreq>
  {{ end }}
</url>
{{ end }}{{ end }}
</urlset>

Create layouts/robots.txt:

Sitemap : {{ $.Site.BaseURL }}sitemap.xml

Edit config.toml:

enableRobotsTXT = true

The sitemap is available at /sitemap.xml.