Deploying a Hugo site to Azure Storage using GitHub Actions

Recently I decided to change blog platform and after various interactions with the Ruby-based Jekyll (which integrates great with GitHub Pages) as well some time spent with Vue.js and Nuxt, I finally decided upon a statically-generated site using Hugo. It’s so nice to write blog posts using Markdown (and linting using the excellent markdownlint Visual Studio Code extension).

As I am statically generating my site, I decided to use Azure Storage with one of its more recent features - the ability to serve static content (HTML, CSS, JavaScript and image files) from a specially-named $web container - this offers a great cost-effective way to host some static sites.

Don’t confuse using Azure Storage blob storage with the new “Azure Static Web Apps” which has made a real splash at the Microsoft Build 2020 conference. I would use Static Web Apps if I didn’t need to point my apex domain ( at it. If you also have that problem and want a temporary solution, checkout: How to configure a root domain in an Azure Static Web App

Azure Portal showing the $web container on my Azure Storage account

Figure: Azure Portal showing the $web container on my Azure Storage account

YAML blah blah

My good friend and fellow MVP, Shahid Iqbal wrote an excellent post about Deploying a Hugo site to Azure Storage static website hosting using Azure DevOps and you should go and read it if you haven’t already. As I have been moving more of my repos to GitHub of late, it left me wondering how I would build a GitHub Workflow to do something similar, storing my workflow in YAML format. I didn’t have too look far to find GitHub Actions I needed:

  1. Checkout. “This action checks-out your repository under $GITHUB_WORKSPACE, so your workflow can access it”. Makes sense.
  2. GitHub Action for Hugo from Jake Jarvis. The nice thing about this is that it supports running Hugo Extended (which is required if you are using SCSS on your website) and each Hugo release has an accompanying GitHub Action version.
  3. Azure Static Website Action from Tiboriu Covaci. This action is completely written for Node.js so avoids the Azure CLI on your build agent. As a result it is fast. We just need to feed it the connection string which we can store in a GitHub Secret so that only our builds have access to it.

There are ways to get Hugo to directly upload to Azure Storage, however it relies on the Azure CLI being installed to do the work and I found the native solution performs nicely and is a pretty neat solution.

Azure Storage connection string

To get the connection string from your Azure Storage account, you’ll need to go to Settings > Access Keys in the Azure Portal. There are two keys so that you can use either and rotate your keys in the event they get compromised. Just copy one of the connection string:

Finding the connection string on Azure Storage

Figure: Finding the connection string on Azure Storage

GitHub Secrets

Once we have that, we can go to GitHub in our browser, and add a secret named AZURE_STORAGE_CONNECTION_STRING and paste in the value:

Updating the secret

Figure: Location of GitHub Secrets: Settings > Secrets

GitHub Workflow

As GitHub workflow definitions are stored in the repo, all you have to do is check in the following file: .github/workflows/main.yml and push. In just 16 lines you too can be releasing your website on every git push:

name: Hugo deploy
    branches: [master]

    runs-on: ubuntu-latest
      - uses: actions/[email protected]
      - uses: jakejarvis/[email protected]
      - uses: tibor19/[email protected]
          enabled-static-website: 'true'
          folder: 'public'
          connection-string: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}

The whole thing took less to time to write and get working than formatting this blog post!

You will note that instead of using @latest everywhere, I am “pinning” to specific versions of each action. I did this because I did not want the risk of a deployment taking down my website and I felt this was less likely if I fixed the versions. There are of course reasons to ‘ride latest’ but that’s an argument topic for another day!


I’m not going to go into detail on GitHub Actions other than to say you should be using it! All account types come with plenty of free build minutes so there’s no excuse not to! But Azure Static Web Apps are the future in this space and you’ll see how we can use the above GitHub Actions to work with it in future blog posts.