Hugo Hosting with KeyCDN

hugo hosting

Hugo is a modern static site generator that’s written in Go and built to provide an optimal writing experience for authors and viewing experience for visitors. Static site generators have been growing in popularity over the last few years as they are much less resource intensive, provide faster speeds, better security, and are simpler.

Hugo is currently one of the most popular static site generators available. This guide shows you how to accelerate your static site even more for users around the globe by using a Hugo hosting and KeyCDN setup.

Apart from using Hugo, this tutorial also uses a GitLab repository with their built in CI for options 1 and 2 while a Bitbucket integration is outlined for options 3 and 4.

Before starting the integration, the commands below show how to setup a simple “hello world” Hugo page. Note that there is a git submodule being used which in turn leads to git submodule commands in below CI job definitions.

hugo new site ciexample
cd ciexample
git init
echo "/public" >> .gitignore
echo "User-agent: *\nDisallow:" > static/robots.txt
git add .
git commit -am init

git submodule add -b master https://github.com/spf13/herring-cove.git themes/herring-cove
git submodule init
echo 'theme = "herring-cove"' >> config.toml
git commit -am "added herring-cove theme"

hugo new about.md
vim content/about.md
hugo undraft content/about.md
git add content/about.md
git commit -am about

Option 1: Host Your Static Site as a Gitlab Page Behind a KeyCDN Pull Zone

If you rather pull your files from a pre-existing origin server and have your files update immediately upon purging, running a pull zone in front of a GitLab page might be the solution for you.

The site will be running on GitLab with a URL of “https://youruser.gitlab.io/reponame/”. Set up a pull zone to point to this location – while the origin location doesn’t exist yet, you will need to use your new Zone URL address (or Zonealias) in the below .gitlab-ci.yml file as the BASEURL variable.

The .gitlab-ci.yml file for this option looks slightly different:

image: alpine:latest

variables:
    BASEURL: "https://cipull-7bb7.kxcdn.com/"
    HUGO_VERSION: "0.26"
    HUGO_CHECKSUM: "67e4ba5ec2a02c8164b6846e30a17cc765b0165a5b183d5e480149baf54e1a50"
    KEYCDN_ZONE_ID: "75544"

before_script:
    - apk update
    - apk add curl

pages:
    stage: deploy
    script:
    - apk add git
    - git submodule update --init
    - curl -sSL https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
    - echo "${HUGO_CHECKSUM}  /tmp/hugo.tar.gz" | sha256sum -c
    - tar xf /tmp/hugo.tar.gz hugo -C /tmp/ && cp /tmp/hugo /usr/bin
    - hugo --baseURL ${BASEURL}
    - curl "https://api.keycdn.com/zones/purge/${KEYCDN_ZONE_ID}.json" -u "${KEYCDN_API_KEY}:"
    artifacts:
    paths:
    - public
    only:
    - master

Instead of your KeyCDN user name and SSH key pair (as you’ll need in option 3), you will have to specify the Zone ID and your KeyCDN API key as a secret variable. The Zone ID and API key are used to purge your zone – it’s not strictly needed but otherwise, the CDN might deliver older versions of your assets for quite a while.

Push your changes to GitLab:

git remote add origin git@gitlab.com:youruser/ciexample.git
git push -u origin master

After verifying your CI job ran without issues, first check that your GitLab page shows up under https://youruser.gitlab.io/reponame/ (it might look broken depending on your browser settings as all links point to your KeyCDN zone – don’t worry about that) and then by heading to whatever Zonealias / Zone URL you defined.

Option 2: Using a Pull Zone with Bitbucket

Bitbucket works a bit different from the GitLab example above in that you need to create a repository with a certain name and then commit your HTML files to that repository. In this example, we use one repository to hold the Hugo code, configuration, and CI pipeline as shown in the previous example and one to hold the result of that CI pipeline as HTML.

First, we’ll setup the repository holding the code as described in the example for the push zone above. We divert from that with setting different environment variables just like we used in the GitLab with pull zone example.

bitbucket keycdn api

The name of the new repository that will hold your actual page needs to follow a certain schema. It is either named after your user or after your team in the format <name>.bitbucket.io. In our case, this will be keycdn-demo.bitbucket.io:

bitbucket new repo

To allow the CI pipeline of our code repository to push to this, we have to add the public SSH key of our code repository to the account access list of an account having access to the repository. This is necessary because the per-repository SSH keys are read-only and would not allow us to push the generated HTML. Keep in mind that this gives the CI pipeline access to all this account’s repositories – if more people have access to this repository, you might want to use a separate account for holding it.

Put the following in your bitbucket-pipelines.yml – adjust the URL to your pages repository accordingly.

image: alpine:latest
 
pipelines:
    branches:
        master:
            - step:
                script:
                    - apk update && apk add curl git openssh rsync
                    - git submodule update --init
                    - curl -sSL https://github.com/gohugoio/hugo/releases/download/v0.26/hugo_0.26_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
                    - echo "67e4ba5ec2a02c8164b6846e30a17cc765b0165a5b183d5e480149baf54e1a50  /tmp/hugo.tar.gz" | sha256sum -c
                    - tar xf /tmp/hugo.tar.gz hugo -C /tmp/ && cp /tmp/hugo /usr/bin
                    - git clone git@bitbucket.org:keycdn-demo/keycdn-demo.bitbucket.io.git /tmp/page && rm -fr /tmp/page/*
                    - hugo --baseURL "http://cipull-7bb7.kxcdn.com/" && mv public/* /tmp/page/
                    - git config --global user.name "Hugo CI" && git config --global user.email "hugo@example.com"
                    - cd /tmp/page && git add . && git status && git commit -am "CI Hugo run" && git push -u origin master
                    - curl "https://api.keycdn.com/zones/purge/${KEYCDN_ZONE_ID}.json" -u "${KEYCDN_API_KEY}:"

You can then head to Pipelines and check on your CI job:

bitbucket ci jobs

After verifying your CI job ran without issues, check that your Bitbucket page shows up under https://<name>.bitbucket.io (it might look broken depending on your browser settings as all links point to your KeyCDN zone – don’t worry about that) and then by heading to whatever Zonealias / Zone URL you defined.

Option 3: Using a Push Zone with GitLab

If you want to host your Hugo site completely on KeyCDN, your first step will be to create a push zone. Make sure you enable Directory Index in the advanced settings of your zone.

directory index enabled

You’ll likely want to use your own Zonealias for your website instead of the generic Zone URL (e.g. cipush-7bb7.kxcdn.com) we use in this example. Define this alias now and substitute it below for the Zone URL.

Create a .gitlab-ci.yml file describing the automated build jobs that will happen every time changes are committed to the repository. Make sure to set your username accordingly.

image: alpine:latest

variables:
    BASEURL: "https://cipush-7bb7.kxcdn.com/"
    HUGO_VERSION: "0.26"
    HUGO_CHECKSUM: "67e4ba5ec2a02c8164b6846e30a17cc765b0165a5b183d5e480149baf54e1a50"
    KEYCDN_USER: "youruser"
    KEYCDN_ZONE_NAME: "cipush"

before_script:
    - apk update
    - apk add curl

hugo:
    stage: build
    script:
    - apk add git
    - git submodule update --init
    - curl -sSL https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
    - echo "${HUGO_CHECKSUM}  /tmp/hugo.tar.gz" | sha256sum -c
    - tar xf /tmp/hugo.tar.gz hugo -C /tmp/ && cp /tmp/hugo /usr/bin
    - hugo --baseURL ${BASEURL}
    artifacts:
    paths:
        - public

push_keycdn:
    stage: deploy
    script:
    - apk add openssh rsync
    - mkdir -p ~/.ssh
    - echo 'rsync.keycdn.com,185.172.149.122 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFM7Jqs3BqC+MSEoVsZ+YMKTjVIMTSKlZX2+0t88o4LZvd+BWt71SkXv4mQ↪ r7xKD59m7jeJcWiO43u7YQzi+Tgg=' >> ~/.ssh/known_hosts
    - echo "${SSH_DEPLOY_KEY}" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
    - rsync -avz --delete --chmod=u=rwX,g=rX public/ ${KEYCDN_USER}@rsync.keycdn.com:zones/${KEYCDN_ZONE_NAME}/
    only:
    - master

Create a GitLab repository for your website as well as an SSH key pair that will be used to push the generated data to a KeyCDN push zone.

For sensitive information like the SSH key, we use a secret variable to store the Private key with our GitLab project. Secret variables can be defined under Settings -> Pipelines -> Secret variables.

gitlab secret variables

The public key will be stored in the KeyCDN dashboard under Account Settings -> Authentication -> Rsync over SSH Authentication.

public key rsync

Finally, it’s time to push the newly created repository to GitLab:

git remote add origin git@gitlab.com:youruser/ciexample.git

git push -u origin master

You can watch the progress and CI job output in your Gitlab project under “Pipelines”:

gitlab pipelines

You can now head over to your Zonealias URL for your brand new Hugo website that’s fully hosted over KeyCDN.

Option 4: Using a Push Zone with Bitbucket

This option is the Bitbucket version of Option 3. Bitbucket Pipelines are included in all bitbucket plans (to some extend). The first step to configuring your Hugo site to be delivered via a KeyCDN push zone with Bitbucket is to configure your SSH key (public and private) under projects settings -> ssh keys -> add private & public keys

public and private keys

Also, add rsync.keycdn.com as a known host:

known host

In Bitbucket, variables are set under projects settings -> environment variables. We use the following in our CI pipeline:

bitbucket environment variables

With all prerequisites in place, we can now create our bitbucket-pipelines.yml file to define our CI job. With Bitbucket, this can be done through the Web UI when enabling Pipelines for your repository. Replace the example template with the following:

image: alpine:latest
 
pipelines:
    branches:
        master:
            - step:
                script:
                    - apk update
                    - apk add curl git openssh rsync
                    - git submodule update --init
                    - curl -sSL https://github.com/gohugoio/hugo/releases/download/v0.26/hugo_0.26_Linux-64bit.tar.gz -o /tmp/hugo.tar.gz
                    - echo "67e4ba5ec2a02c8164b6846e30a17cc765b0165a5b183d5e480149baf54e1a50  /tmp/hugo.tar.gz" | sha256sum -c
                    - tar xf /tmp/hugo.tar.gz hugo -C /tmp/ && cp /tmp/hugo /usr/bin
                    - hugo --baseURL "http://cipush-7bb7.kxcdn.com/"
                    - rsync -avz --delete --chmod=u=rwX,g=rX public/ ${KEYCDN_USER}@rsync.keycdn.com:zones/${KEYCDN_ZONE_NAME}/

Your CI job will run after you saved this and you can watch its progress.

pipeline progress

 

 

Summary

There are a few ways to setup Hugo hosting with KeyCDN as seen in the examples above. Depending upon your current environment and needs will determine whether you want to use a pull zone vs a push zone. Similarly, you can substitute Gitlab with Github and any of their CI integrations, Bitbucket with Bamboo or others. If you already have an in-house CI solution, pushing to a KeyCDN push zone works just as well.

2 Comments

  1. Mario I.

    Thanks! I hope that you can create a generic tutorial how to serve static html sites on all hosting. Or can we use only your CDN also as hosting?

Leave a Reply to Cody Arsenault Click here to cancel reply.