Picture of a lake in Canada

Hugo, GitLab, Azure and Cloudflare

February 3, 2019

My new blog is powered by a few different technologies and in this post I will run through some of the steps required to get it setup. It wasn’t as straight forward as I had hoped so I will document some of the problems I encountered and how I overcame them.

First of all the blog is powered by the following stack:

  • Hugo - a static website generator
  • GitLab - git source control & Continuous Deployment (CD) platform
  • Azure Blob Storage - static website hosting
  • Cloudflare - DNS / TLS / Web optimisation service

Hugo

Hugo was pretty easy to get started with thanks to the tutorial. Once I got the site created I started to configure it via the config.toml and fill in the placeholders. After completing that I set about finding a suitable theme and picked Onepress which is a minimalistic and responsive theme for hugo. Having completed the installation steps for the theme I made a couple of changes to the theme’s pages so that the author card would be displayed and also so that you could see a bit more of my banner image.

Prior blogging and migration

As part of my university course I was encouraged to blog about the various modules I took throughout my studies. To facilitate that I used BlogEngine.NET to write my blog posts. Having lost interest in blogging some time after finishing my degree I took the whole website offline and archived my old blog posts. Fortunately Jijie Chen wrote a tool to migrate from the BlogML format to hugo markdown called BlogML2Hugo which mostly worked a treat. A few of my blog posts had quotes in the title and it didn’t escape them so that needed fixing after migration (which wasn’t a big problem!). The new markdown files slotted into hugo’s site structure. I did have to tinker a little with the markdown removing the [more] tags and any site specific styling to get everything hugo ready.

I had completely forgotten that I had registered the mrwade.co.uk domain name previously so I set about registering an alternative, as the tool I had been using to check domain name availability said that it was already registered to someone… Fortunately I realised that I had registered it before and it was still available despite having let it lapse. After completing the name registration I set about moving the names to cloudflares DNS servers using their fantastic free plan.

Azure and Cloudflare

One of the perks of working at C5 is that we have MSDN subscriptions and as part of that benefit we have some free usage credits on Azure. The most expensive part of hosting this blog will be the domain name registration as there should be enough credits to cover the blob storage costs & data egress charges. Unless of course this blog blows up (in which case cloudflare’s caching should save me 😉). As the tutorial I linked to earlier suggests it is possible to host a static website using blob storage which is what I chose to do. In order to use a custom domain name you need to follow this blob storage guide. Part of the configuration is to add verification CNAME records these took a little while to propagate so I left that overnight and Azure let me verify the domain in the morning.

To make the most of cloudflare’s functionality I turned on all of the options for HTTPS including redirection, end-to-end encryption and some redirection rules pointing to https://www.mrwade.co.uk. The free plan also includes caching capabilities & auto html/js/css minification.

Cloudflare crypto setup: SSL = Full, Always use HTTPs = Yes, Automatic HTTPS rewrites = Yes Cloudflare crypto settings

Cloudflare page rule setup: Redirect from mrwade.co.uk/ to https://www.mrwade.co.uk/ Cloudflare page rule

GitLab

Once all of the plumbing was in-place I was ready to deploy the published site built by hugo. To make the whole write->publish process easier I wanted to automate the deployment step as much as possible. As I am using GitLab I thought I would try out their new(ish) CI/CD capabilities, this was the most tricky part of the process but I don’t have a great deal of experience with CI/CD platforms so I likely made a few mistakes that more experience people would avoid.

The process looks like this:

  1. Write post (hugo new ...)
  2. git commit & git push
  3. CD:
    • Get latest
    • Hugo publish
    • Move files to Azure Blob Storage container
  4. Profit!

The following yaml achieves the above steps:

stages:
  - build
  - deploy

build:
  stage: build
  image: monachus/hugo
  script:
  - git submodule update --init --recursive
  - hugo -d public_html
  cache:
    paths:
    - public_html
  artifacts:
    paths:
    - public_html
  only:
  - master
 
deploy:
  stage: deploy
  image: hawaku/azcopy
  dependencies:
  - build
  script:
  - azcopy --source public_html --destination $BlogStorageUrl --dest-key $BlogStorageKey --recursive --quiet --set-content-type

For the un-initiated the value of the image properties refer to docker images which contain all of the dependencies and binaries of the tools we need.

The $BlogStorageUrl and $BlogStorageKey environment variables are substituted for real values by the GitLabs job runner. One thing that tripped me up here is that the Azure blob storage container name for the static site is $web and the $ was causing $web to be interpreted as an environment variable. To avoid that the $ had to be escaped by doubling up the $’s. Note that if you dont have --quiet & --set-content-type existing files will not be overwritten, and the content type will be set to application/octet-stream and then all kinds of wierd things will happen when people visit your site.

comments powered by Disqus