Build-A-Blog Part 2
Let’s Start Coding!
In the first part of this series we set up a Hugo-based website using GitLab Pages and our custom domain name. Now that we have it set up and accessible, it’s time to customize it and add content!
NOTE: I use Visual Studio Code, a free coding IDE from Microsoft that has an extensive set of community developed extensions for all sorts of different languages and other purposes. The different extensions can make for a completely different look. For this blog, I have the following extensions enabled:
- Better TOML - Syntax highlighting for TOML code
- Code Spell Checker - Spelling checker for source code
- Markdown All in One - All you need to write Markdown (keyboard shortcuts, table of contents, auto preview and more)
- Markdown Preview Enhanced - Automatic Scroll Sync and so much more
- markdownlint - Markdown linting and style checking
- YAML - Syntax Highlighting for YAML code
The TOML and YAML extensions give me syntax highlighting for those two languages, which makes reading them and finding typos much easier. And since this is a blog with English words, the Code Spell Checker also helps me detect typos in the sentences (shown with a blue squiggle). The remaining three help with Markdown by automatically opening a separate pane to show how the rendered Markdown will look, to automatically scroll the Markdown preview pane with the code pane, and to lint my Markdown code (IE, check it over for errors and for best practices; shown with a yellow or red squiggle).

Git Large File Support
Git was designed around tracking changes to small text files, but any website is going to have large multimedia files in the repository as well. It’s not a terribly big deal for a small site with some simple images, but as your repo gets bigger the git functionality can suffer. So before we start uploading anything, lets go ahead and install Git LFS. Follow the instructions on that website to get it set up on your system, then run git lfs install from your project root directory.
Once that’s done, we want to set it up to track any large files that we’ll be adding to our site. I know off the bat that I’ll be uploading some image files, so I start off with this command to track a set of common image files:
git lfs track "*.jpg" "*.jpeg" "*.png" "*.gif" "*.tif" "*.tiff" "*.ico"
NOTE: "*.svg" might need to be added to this list; they’re technically text files though, so can benefit from git version tracking if you’re editing them. On the other hand, most people edit their SVG’s in a vector image app and just upload the finished product. Just remember that it’s much easier to start lfs tracking a file type before the file is added to the repo.
Git LFS uses the .gitattributes file, so lets make sure we add that to our repository with git add .gitattributes.
GitLab includes support for LFS by default, so now any images you upload will be marked with the LFS tag.

NOTE: If you’re not familiar with Git LFS, please keep in mind that Git LFS needs to be installed on any host before cloning the repository. But if it’s already installed on your machine, then git clone will work mostly as expected. If your repo has a lot of LFS-tracked files, however, you’ll likely see better performance with git lfs clone instead.
Out With The Old
Our first step is to clear out the existing theming from our new website. Don’t get me wrong, the Beautiful Hugo theme that GitLab initialized our code repository with looks great! But it uses quite a few javascript and css files. I wanted to start with something simpler so I could get a good grip on the basics of Hugo programming, and then add what I needed later.

Obviously the two folders in themes have to go, but we also want to remove everything from the content folder, as these all depend on files in the themes folder. Finally, we’ll want to clear the config.toml file as it is also dependent on the themes folder.
Git Commit Time
This is a good time to commit your changes to your local Git repository. If you’re not familiar with this process, I strongly recommend that you take a look at the first 2 chapters (at least) of the amazing and free ebook Pro Git. VSCode also fully supports Git; you can add files and make commits to the local repository very easily from the version control tab in the sidebar, and even push code up to the remote GitLab repository. It’s generally better to commit more often than less often and at a minimum I’d recommend doing so at the end of each of these sections. However, it would break up the narrative flow a bit too much to remind you every time so I’m going to leave it without saying.
You can also push your changes after a commit to the GitLab remote repository, but this is generally only done when you’ve completed a particular feature or for other reasons when you’re working with multiple people on the same project. The main rule of thumb is to only push code that doesn’t break anything! The GitLab CI/CD pipeline won’t deploy the codebase if it detects any breaking problems in any case.
NOTE: One more note on Git: you may notice from the screenshots that I’m making all commits directly to the master branch. This is not best practice! If you’re not familiar with branching, I strongly recommend that you review Chapter 3 of the Pro Git ebook linked above and the GitLab Flow documentation for a great set of best practices for branching with GitLab. The reason all my screenshots show that I’m coding against the master branch is because I actually already did all this work in a different repo, and then created this one just so I could get screenshots so I already knew everything that needed to happen….
Hugo Themes
Now we just need to pick a new theme and get it installed!
Let’s head over to the Hugo Community Themes page. They have hundreds of free themes to choose from, and many of these theme authors also have additional themes for sale with even more features and support provided. Each theme has a set of tags attached to it, and you can use the links on the right side to help filter it down a bit. In my case, I wanted something simple so I clicked on the Minimal tag. I also wanted something with a sidebar, so I just scrolled and opened any I saw in a separate tab.
NOTE: Keep in mind as you’re looking through the gohugo.io website that it’s entirely coded with Hugo. If you see something cool on their website, it’s possible to do on yours, too!
To narrow down the possibilities, I first got rid of themes that were based on a theme from another platform. These often have a core of code designed for something else with a nice fresh coat of Hugo paint slathered on top. I was looking for something programmed from the ground up with the Hugo paradigm. That narrowed the choices down considerably. My next step was to take a look at the remaining themes’ code bases to see how complicated they were. The m10c theme by vaga really stood out for me; it was very simply coded with the just the necessary .scss styles, page layouts, and partial templates. It was perfect for my project.
The README.md file for this theme (and a whole lot of others) advises you to git clone the theme into your repository, but there’s a better way using git submodules. Submodules allow us to essentially keep separate git repositories inside our own. So from the root of our project we’ll do:
git submodule add git@github.com:vaga/hugo-theme-m10c.git themes/m10c
NOTE: This command is the SSH version; to use this you’ll need to create an account with GitHub (where this repo is hosted) and add your SSH key. The instructions are basically identical to what we did with GitLab in Part 1 of this series. Otherwise feel free to use the HTTPS version (https://github.com/vaga/hugo-theme-m10c.git); we won’t be pulling or pushing code to this repo very often.
NOTE: Keep in mind that when using git submodules, there’s an extra step after cloning the repo to a new machine. You’ll want to clone the repo as normal; this will create the submodule directory structure but won’t bring down any actual files. So you’ll need to initialize and pull down the submodule files like this:
git clone **code repo URL**
git submodule init
git submodule update
Making the Site Our Own
With the theme loaded, we want to repopulate our content folder and config.toml file. Most themes have an exampleSite subdirectory, so all we have to do is copy everything from that directory to the root of our project:
cp -r themes/* .
All that we have to do now is a quick edit to the config.toml file and we can start up the site.

The most important thing to change here is the themesDir setting. It’s set this way because this file used to live in themes/m10c/exampleSite/config.toml, so going up two directory levels points it at themes. But now that points to who-knows-where, so lets just remove it (the default for this option is themes, which is how we’re set up).
While you’re here, feel free to update the baseURL, title, author, description, and the social media links. Here’s mine now:

So let’s see how this looks! Hugo comes with a live reload web server baked right in, so we can simply run the server command from the root of our project directory:
hugo server
Now we open up our browser to localhost:1313 to see what we’ve got!

So this is a great start! But we definitely want to do a few quick things to personalize it further. First up is replacing that silhouette. All you need for this is a square image; the theme will stretch it to square and then circle it up. So if it’s not square to begin with you could see some weird effects.
Hugo likes you to store any files that don’t need compiling in the static directory, and that definitely includes images. You can organize this however you like, but I just created a folder called static/img and dropped my profile pic in there as ctflora.png.
Then in the config.toml file, we’ll add a line to the [params] section:
[params]
author = "Chris Flora"
description = "Follow along as I document my HomeLab adventures and misadventures!"
avatar = "/img/ctflora-1.png"
As soon as you save this file, the hugo server will automatically recompile and refresh your tab. It’s so fast that it will likely be done before you can bring that tab to the front. But you should see your pic in the circle now! If not, check your terminal to ensure that the hugo server is still running, and if it is check to see if it threw any errors. The most likely problem at this point is a typo in the config.toml, or that you dropped the image in the wrong folder.
Our First Blog Post
Finally, we want to make our own blog post. Hugo makes this super easy; all you have to do is create a new Markdown file in the content/posts directory and it will automatically show up on the list. Let’s give it a try.
Frontmatter
Hugo (and other SSG’s) have a concept called frontmatter in the markdown files. It’s basically a way to include some metadata variables about the post you’re creating. Let’s take a look at one of the posts included with the theme:
+++
title = "Creating a New Theme"
tags = ["hugo", "themes"]
date = "2014-09-28"
+++
What we have here is some TOML code wrapped with a +++ prefix and suffix. As with all files for Hugo, you can actually use YAML or TOML here (YAML would be wrapped in --- prefix and suffix). This is the frontmatter, and after this the actual markdown starts:
## Introduction ##
This tutorial will show you how to create a simple theme in Hugo.
There’s a lot of variables you can add to the frontmatter, but these are a great start. The title is how Hugo knows what to call your post in the post list, the date is what Hugo will use to order the list, and the tags are a very useful way to help your users find posts that interest them. One other very useful one is draft. If this is set to true on a post, then that post will not be rendered by Hugo. This is a great way to work on a post without showing a work-in-progress. However, you can still see them on your development platform by running the Hugo server with the -D command line switch.
Taxonomies
Tags are part of the Hugo concept of Taxonomies which can be an extremely powerful way to organize your content. Hugo automatically provides the tags and categories taxonomies for you. You can check it out by simply pointing your browser to localhost:1313/tags. You can add any tags you want to any post and they’ll automatically get added to this list (same for categories).
If you’re coming from Wordpress, just understand that there’s no underlying differences between tags, categories, or any other taxonomies you add to Hugo. They’re all just keywords you can attach to any post. I’m using tags to flag software & hardware discussed in a post as well as important ideas, series to identify different series of blog posts, and goals to identify the overarching goals I have for my HomeLab.
NOTE: If you’re not familiar with Markdown syntax, it’s basically just a simple way to type a text document and include basic formatting. You can check out a site like Markdown Tutorial for a quick lesson, or just refer to a Markdown Cheatsheet. And with the VS Code extensions I have enabled, I can see a live preview of my rendered markdown while I type:

Hello, Hugo World!
As is the custom when learning a new language or platform, let’s make a simple ‘Hello, World!’ post on our new blog! As mentioned above, it as simple as creating a new Markdown file in the /content/posts directory. In VS Code, just click on that directory and click the ‘New File’ button.

Let’s add some simple frontmatter:
+++
title = "Hello World!"
tags = ["Hello World", "Hugo"]
date = "2020-01-02"
draft = true
+++
And then follow that with some simple Markdown:
# Hello, Hugo World!! #
Welcome to a **new year** of Hugo!
But before we’re done, lets spice it up just a bit. Hugo makes it easy to add images to the markdown, so let’s add one. Copy any image you want to the /static/ directory. Here I’m using a copy of the Hugo logo (provided under the Apache 2.0 license). Then add the following to your post markdown:

You don’t include the /static/ part of the path, because when Hugo builds your website, it moves everything in the /static/ directory into the root directory of your website. So this path is the future location of this image. You can also organize files in the /static/ directory however you like, including subdirectories; all of that structure will remain after the build.
As soon as you save this file, well, nothing happens! Since we added draft = true, the Hugo Server isn’t compiling it. So lets stop the existing server with a CTRL-C, and restart it with the drafts option and the verbose output option:
hugo server -v -D
OK, now reload the webpage in your browser, and voilĂ !

Now feel free to remove the old blog posts from your content/posts directory and push what you have up to GitLab so everyone can see it.
And then it’s time to start making your own content!
What’s Next?
There’s still a lot to do! First we’ll want to figure out a better way to organize my content. Right now, all of the screenshot images are stored under the /static/img/<post-name> folders, but it would be much simple if we could keep all of the media for a particular blog post together. Hugo has the concept of Page Bundles that will probably work perfectly for this!
Then we need to check out the existing CSS/SCSS files and make any changes we want to the styling (like different colors, fonts, grid sizes, do we want to add a header bar or add more info to the sidebar, etc etc). It would also be great to define specific styles for some of my inline notes (like the NOTE: and WARNING: paragraphs); possibly give them a different background color, or a different font, or some other way to distinguish them from the general text but still be able to add it easily to the post markdown. Hugo Shortcodes might be the way to do this.
Then we might want to add some additional page types; in Hugo parlance, this means content that’s not in the /content/posts directory, but a different subdirectory under the content root directory. Maybe an ‘About Me’ page, maybe a page about my HomeLab status and how much it costs. I’ll also need to define pages for my custom taxonomies (Goals and Series); remember that you only get Tags and Categories for free! We haven’t even begun to dig into the template files that Hugo uses to compile the Markdown into HTML and there’s so much customization that can happen there.
And then there’s just so many other upgrades. How about an RSS feed? How about a comment system? How about automatically including a link to the next and previous post in a series? How about an image slideshow or gallery? How about one of those privacy notices required by the EU GDPR legislation?
I guess my point is that there’s always something else to add. I definitely want to add a way to include links to next & previous posts in a series, and my next big addition will be a comments section with a self-hosted comments server. Keep an eye out for the next post in this series!
And as mentioned previously, please reach out to me at christopher@flora.family if you have any questions! We’ll get the comments up someday….