Hugo

Moving my blog to Hugo (Part 1)

Moving my blog to Hugo (Part 1)

Why am I moving

In 2013 I started a blog to record the errors I encountered in my job. Anything interesting or that took me a while to fix. Initially I thought this would help with my writing as I was being asked to produce increasing amounts of documentation, but the biggest benefit was having a catalog of the problems i had solved. I’ve probably read the posts more than anyone else.

I started out hosting the site on Wordpress.com and to be honest, I probably should have left it there. However, I decided to move it to an Azure App Service with a 3rd party hosted MySql database. It was a good learning experiance, but it was costing my about £12 pounds a month. I eventually moved this to in app MySql and this reduced the cost a bit, but I was still getting poor performance for more than I wanted to pay.

I wanted to refresh my blog, but it’s taken me a while to get round to doing something about it. When I finally did, I knew I wanted to do something more than just use a CMS. I had heard of static site generators, but i had really looked into it. I also wanted to use the domain I had registered, but never used (CGFootman.com)

Creating the site

I didn’t do much research into what is the best static site generator, but the two that I did come across, Hugo and Jekyll had one main differentiator. Jekyll needs ruby to run and hugo is a standalone exe. So trying to keep things simple I went with Hugo and so far i’m pretty happy with that decision.

Once I had settled on Hugo I started working through the quick start. This gives you the commands you need to create the site, set a theme and start adding content. I went with a theme called liva-hugo, its bright and clean and had a few interesting features like the featured posts.

Liva Hugo Theme

To install this theme, I followed the instructions in the quick start, saving the liva-hugo folder to the themes folder in the root of the site and then updating the config.toml file.

Once I had my pretty site, I needed to port the posts from my old Wordpress blog. I installed a plugin called Wordpress to Hugo Exporter, you have to upload it to your site but it can be done via the admin interface. The steps you need to follow in the doc are here. It took about 10 minutes to export my posts and gave me a zip file that I could download. It contained all of the pages from my site along with the images.

Just copying the posts to the posts folder in my new site gave me instant content. However, it looked terrible. Images were broken, the code widget I had used was now just a bunch of html in the middle of the post. I went through each post and cleaned this out, also removing an metadata from other plugins I had used in my Wordpress site (Like social media auto posters). It took a long time, but wasn’t that taxing. You work out pretty quickly, what you need to change the code to.

In the below example i have removed the twitter and snap edit lines and updated the image url to the new location.

Top of Exported blog post before updating

---
title: Copy and paste from VSCode without the background
author: cgfootman@hotmail.com
type: post
date: 2019-01-09T21:54:31+00:00
url: /2019/01/09/copy-and-paste-from-VSCode-without-the-background/
featured_image: /wp-content/uploads/2019/01/VSCodeV2.jpg
cwp_meta_box_check:
  - No
twitter_share:
  - 'a:2:{s:8:"hashtags";a:1:{i:0;s:6:"VSCode";}s:4:"text";s:49:"Copy and paste from VSCode without the background";}'
twitter_card:
  - 'a:2:{s:5:"title";s:49:"Copy and paste from VSCode without the background";s:11:"description";s:49:"Copy and paste from VSCode without the background";}'
snapFB:
  - 'a:1:{i:0;a:1:{s:2:"do";s:1:"0";}}'
snap_isAutoPosted:
  - 1547070871
snapEdIT:
  - 1
snapTW:
  - 's:425:"a:1:{i:0;a:12:{s:2:"do";s:1:"1";s:9:"msgFormat";s:59:"New post (%TITLE%) has been published on %SITENAME% - %URL%";s:8:"attchImg";s:1:"1";s:9:"isAutoImg";s:1:"A";s:8:"imgToUse";s:0:"";s:9:"isAutoURL";s:1:"A";s:8:"urlToUse";s:0:"";s:4:"doTW";i:0;s:8:"isPosted";s:1:"1";s:4:"pgID";s:19:"1083119865635004417";s:7:"postURL";s:56:"https://twitter.com/CGFootman/status/1083119865635004417";s:5:"pDate";s:19:"2019-01-09 21:54:34";}}";'
snapImportedComments:
  - 'a:0:{}'
categories:
  - VSCode

---
 

When you paste code, copied from VSCode, you can unfortunately.....

Top of exported blog post after udpating

---
title: Copy and paste from VSCode without the background

type: post
date: 2019-01-09T21:54:31+00:00
url: /2019/01/09/copy-and-paste-from-VSCode-without-the-background/
image: "images/wp-content/uploads/2019/01/VSCodeV2.jpg"

categories:
  - VSCode

---
 
When you paste code, copied from VSCode, you can unfortunately.....

I created my site in a git repo and made a habit of regularly commiting my changes. If you are new to git, checkout this guide from freecodecamp.org. Its pretty good and goes through setting up a github account/repo. My preference is using Azure Devops but as long as you’re using git, its all good.

Regularly committing gives you confidence to make changes to code, I looked at the theme and decided that I wanted to reorder the items in the right hand side bar. I knew I could roll back anything I broke, so I started searching for files that had text from the elements I wanted to move. I found the file in \themes\liva-hugo\layouts\partials\sidebar.html and reordered the code blocks, to put the about section at the top and the tags section at the bottom.

before i edited sidebar.html

<div class="col-lg-4">
  <!-- about -->
  <div class="widget">
    {{ with .Site.GetPage "/about" }}
    <h4 class="widget-title">{{ .Title | markdownify }}</h4>
    {{ if .Params.Image }}
    <img src="{{ .Params.Image | absURL }}" alt=""
      class="img-fluid author-thumb-sm d-block mx-auto rounded-circle mb-4">
    {{ end }}
    <p>{{ .Summary }}</p>
    <a href="{{ .Permalink }}" class="btn btn-outline-primary">Know More</a>
    {{ end }}
  </div>
  <!-- category -->
  <div class="widget">
    <h4 class="widget-title">Category</h4>
    {{- if isset .Site.Taxonomies "categories" }}
    {{- if not (eq (len .Site.Taxonomies.categories) 0) }}
    <ul class="list-unstyled">
      {{- range $name, $items := .Site.Taxonomies.categories }}
      <li><a
          href="{{ `categories/` | relLangURL }}{{ $name | urlize | lower }}">{{ $name | title | humanize }}</a>
      </li>
      {{- end }}
    </ul>
    {{- end }}
    {{- end }}
  </div>
  <!-- Tags -->
  <div class="widget">
    <h4 class="widget-title">Tag</h4>
    {{- if isset .Site.Taxonomies "tags" }}
    {{- if not (eq (len .Site.Taxonomies.tags) 0) }}
    <ul class="list-inline">
      {{- range $name, $items := .Site.Taxonomies.tags }}
      <li class="list-inline-item"><a class="d-block p-2 bg-primary text-white"
          href="{{ `tags/` | relLangURL }}{{ $name | urlize | lower }}">{{ $name | humanize }}</a></li>
      {{- end }}
    </ul>
    {{- end }}
    {{- end }}
  </div>
  <!-- social -->
  <div class="widget">
    <h4 class="widget-title">Social</h4>
    <ul class="list-inline social-links">
      {{ range .Site.Params.social }}
      <li class="list-inline-item"><a href="{{ .link | safeURL }}"><i class="{{ .icon }}"></i></a></li>
      {{ end }}
    </ul>
  </div>
  <!-- advertisement -->
  <div class="widget">
    <img src="{{`images/promotion.png` | absURL}}" alt="" class="img-fluid">
  </div>
</div>

after i edited sidebar.html

<div class="col-lg-4">

  <!-- category -->
  <div class="widget">
    <h4 class="widget-title">Category</h4>
    {{- if isset .Site.Taxonomies "categories" }}
    {{- if not (eq (len .Site.Taxonomies.categories) 0) }}
    <ul class="list-unstyled">
      {{- range $name, $items := .Site.Taxonomies.categories }}
      <li><a href="{{ `categories/` | relLangURL }}{{ $name | urlize | lower }}">{{ $name | title | humanize }}</a>
      </li>
      {{- end }}
    </ul>
    {{- end }}
    {{- end }}
  </div>
    <!-- about -->
    <div class="widget">
      {{ with .Site.GetPage "/about" }}
      <h4 class="widget-title">{{ .Title | markdownify }}</h4>
      {{ if .Params.Image }}
      <img src="{{ .Params.Image | absURL }}" alt=""
        class="img-fluid author-thumb-sm d-block mx-auto rounded-circle mb-4">
      {{ end }}
      <p>{{ .Summary }}</p>
      <a href="{{ .Permalink }}" class="btn btn-outline-primary">Know More</a>
      {{ end }}
    </div>
    <!-- social -->
    <div class="widget">
      <h4 class="widget-title">Social</h4>
      <ul class="list-inline social-links">
        {{ range .Site.Params.social }}
        <li class="list-inline-item"><a href="{{ .link | safeURL }}"><i class="{{ .icon }}"></i></a></li>
        {{ end }}
      </ul>
    </div>
      <!-- Tags -->
  <div class="widget">
    <h4 class="widget-title">Tag</h4>
    {{- if isset .Site.Taxonomies "tags" }}
    {{- if not (eq (len .Site.Taxonomies.tags) 0) }}
    <ul class="list-inline">
      {{- range $name, $items := .Site.Taxonomies.tags }}
      <li class="list-inline-item"><a class="d-block p-2 bg-primary text-white"
          href="{{ `tags/` | relLangURL }}{{ $name | urlize | lower }}">{{ $name | humanize }}</a></li>
      {{- end }}
    </ul>
    {{- end }}
    {{- end }}
  </div>
</div>

I tested it by running the hugo server command from within my site folder and then pointing my browser to the url it gave me. I could see the change worked, so I commited the code, if it didn’t I would just revert the change.

❯ hugo server --buildDrafts
Building sites …
                   |  EN
-------------------+-------
  Pages            |  240
  Paginator pages  |   47
  Non-page files   |    0
  Static files     | 5232
  Processed images |    0
  Aliases          |   80
  Sitemaps         |    1
  Cleaned          |    0

Built in 38361 ms
Watching for changes in C:\git\bodgersMSLab\bodgersmslab\{archetypes,content,data,layouts,static,themes}
Watching for config changes in C:\git\bodgersMSLab\bodgersmslab\config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

Change detected, rebuilding site.
2020-05-25 21:14:51.660 +0100
Source changed "C:\\git\\bodgersMSLab\\bodgersmslab\\content\\blog\\2020-05-24-moving-my-blog-to-hugo-part1.md": WRITE
Total in 3050 ms

Reverting the change is easy if you use VSCode, you can just click the back arrow in the git view and it will discard your uncommitted change.

Liva Hugo Theme

If you aren’t using VSCode, then you can use the a standard git command to revert uncommitted changes

git reset

Architecture of the site

I read some amazing articles when trying to come up with the right architecture for this site. This post by Andrew Connell gave good outline of what I needed to create. I knew I wanted to automate the deploy of the site and to do that i needed the Azure ARM templates. So I started by manually deploying the components in azure. Firstly creating the dev site. It looked like this

if you like this diagram check out https://cloudmaker.ai/

Liva Hugo Theme

Once the infrastucture was deployed and working, I went to the resource group and then used the export template option to save the ARM template.

Liva Hugo Theme

Going through the template, I parameterised the names of resources so that I could use the same template with different parameter files. Initially the idea was I would have identical prod and dev environments. Which is a great idea in a work situation where they have money, but not so great in a non work situation. So for a dev environment I just have a storage account with https website enabled.

There are some things you can’t set via ARM or are easier not using ARM. For example I want all of my resources to send their diagnostic information to log analytics. Mainly so I can pretend that I know how to write killer kql queries. To configure this I used a PowerShell script which is called as part of my Azure DevOps pipeline.

The script, which is available in the companion files at the bottom of post, loops through the resources in the resource group and configures supported resource types to send their diag information to log analytics using the below command.

Set-AzDiagnosticSetting -ResourceId $azResource.ResourceId -WorkspaceId $lawId -Enabled 1 -Verbose

The Next Post

In this post I have covered creating the site and the infrastructure, but no real details of the deployment process or the extra bits I added to the site. This is covered in part 2 of this series. If you have any comments or questions relating to this or any post on this site, please uses the comments section.

Companion Files

The companion files to this article, can be found here

Below are some of the links I used while writing the posts. I didn’t implement everything discussed in theses articles, but they all helped.

Configure an Azure Web App to redirect

Adding in Article Ads to Hugo

Adding Google Analytics and AdSense to a Hugo website

Deploying a Hugo site to Azure Storage static website hosting using Azure DevOps

Native HUGO Deployment to Azure

Official deployment docs from Hugo.io

Up & Running With Hugo Part I: Building Your First Site

How to start a blog using Hugo

CI with Hugo and Azure DevOps

Running Hugo on Azure for $2 a month

Host your Hugo site on Azure Storage

Purge Azure CDN With PowerShell

Hugo VSCode Plugin