Building a Blog with Hugo and GitLab Pages

Building a Blog with Hugo and GitLab Pages

Table of Contents

Setting up a personal blog doesn’t have to be expensive or complicated. In this guide, I’ll walk you through creating and hosting a blog using Hugo (a fast static site generator) and GitLab Pages (free hosting) - complete with a custom domain name and SSL certificate. The best part? Outside of the cost of a domain name it’s completely free!

Why Hugo?

If you don’t need any fancy interactive features or server side functionality, a static site makes a lot of sense for serving a simple blog site. You won’t need any server-side logic other than a bucket of files, and as the content is always the same then those files can be optimized at build time and then just sent to browsers as required. This opens up a lot of cheap hosting options, like S3 buckets or, in this case, GitLab pages.

GitLab pages come for free with every repository, and if you are version controlling your content in GitLab it’s but a small extra step to get GitLab to also deliver the site. Add to this the option of using your own domain name rather than the sometimes clunky names GitLab will allocate automatically then it’s hard to find a simpler way of serving your readers.

There are a number of static site generators (SSGs), such as Next.js, Jekyll and Gatsby. One of the easiest options to get started with, and the technology behind the post you are reading now is Hugo - it offers great functionality out of the box, but also allows you a high level of customisation options if you want to get deep into the weeds.

You can read about hugo here: https://gohugo.io/

Prerequisites

Before we begin, make sure you have:

  • Git installed on your computer
  • A GitLab account
  • A text editor
  • Basic command line knowledge
  • A domain name under your control (optional, but recommended)

Let’s Go!

Step 1: Install Hugo

First, let’s install Hugo on your local machine:

  • Windows
  • Linux
  • macOS
choco install hugo -confirm
sudo apt install hugo
brew install hugo

Verify the installation:

hugo version

Step 2: Create a New Hugo Site

Create a new Hugo site and navigate into it:

hugo new site my-blog
cd my-blog

Step 3: Add a Theme

Hugo sites need a theme. You can choose from a selection of over 200 themes here: https://themes.gohugo.io/

Different themes might have slightly different installation instructions, we shall follow the procedure to add a popular theme called PaperMod:

git init
git submodule add https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod

Update your config.toml file to use the theme:

baseURL = 'https://your-domain.com'
languageCode = 'en-us'
title = 'My Blog'
theme = 'PaperMod'

Step 4: Create Your First Post

Create a new post:

hugo new posts/my-first-post.md

Now you can edit then content/posts/my-first-post.md file. The first section contains metadata which determines the order of posts (by date), their titles and whether or not the post should be live or draft. The second section is where you should place your markdown formatted content. If you are new to markdown, there is a great guide here: https://www.markdownguide.org/basic-syntax/

---
title: "My First Post"
date: 2025-01-07
draft: false
---

Hello, world! This is my first blog post.

To preview your site locally:

hugo server -D

Visit http://localhost:1313 to see your site. You can edit the markdown and your browser will automatically update to show the changes whenever you save your document.

Step 5: Set Up GitLab CI/CD

To build the files you’ll be serving to your readers you can run the following command:

npm run build

This will create a public folder with the necessary html, css and image files. It’s possible to copy these files to the webserver of your choice, but as we’re going to use GitLab pages, we can make this happen automatically by adding a single file whic will instruct GitLab to do the building and copying whenever a new commit is pushed to the repository.

Create a .gitlab-ci.yml file in your project root:

image: registry.gitlab.com/pages/hugo:latest

variables:
  GIT_SUBMODULE_STRATEGY: recursive

pages:
  script:
    - hugo
  artifacts:
    paths:
      - public
  only:
    - main

Step 6: Push to GitLab

Now we are ready to create our first public version of the site. Create a new repository on GitLab, then push your code:

git remote add origin git@gitlab.com:username/my-blog.git
git add .
git commit -m "Initial commit"
git push -u origin main

Step 7: Configure GitLab Pages

  1. Go to your GitLab project’s settings ‘Deploy > Pages’
  2. A unique domain name should have been allocated to your site in the form of https://xxxxxxxxxxxxx.gitlab.io/

At this point you can make your GitLab pages site available to the general public by going to the ‘Settings > General > Visibility’ section of your GitLab repository and selecting ‘Everyone With Access’ in the ‘Pages’ dropdown.

If you’d like a friendlier name and have (or intend to buy) a domain name that you control, you can continue with the following steps.

Step 8 (Optional): Add a Custom Domain with SSL

  1. Go to your project’s settings ‘Deploy > Pages’
  2. Click “New Domain”
  3. Enter your domain (e.g., blog.example.com)
  4. Check “Automatic certificate management”
  5. GitLab will provide a DNS record which you will need to add to your domain via your domain registrar: e.g. _gitlab-pages-verification-code.devopsinsights.blog TXT gitlab-pages-verification-code=7e42d83799894a24xxxxxxxxxxxxxxxx This code would mean that you should
    • navigate to the DNS management page of your domain registrar
    • add a DNS record
    • of type TXT
    • with name _gitlab-pages-verification-code
    • and data 7e42d83799894a24xxxxxxxxxxxxxxxx
  6. You will also need to add an ALIAS record to point your domain to the GitLab pages site
    • navigate to the DNS management page of your domain registrar
    • add a DNS record
    • of type A
    • with name @
    • and data 35.185.44.232

There are full instructions on the GitLab website here: https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/

Writing and Publishing Content

Once you have setup your site, you’ll probably want to create more posts over time. This is an extremely simple process, and you might not need to configure anything ever again if you’re happy with your templates and domain name.

To create new blog posts:

  1. Run hugo new posts/post-name.md
  2. Edit the markdown file in content/posts/
  3. Commit and push your changes
  4. GitLab CI/CD will automatically build and deploy your site

Tips for Success

  1. Organize Your Content: Use Hugo’s content organization features like categories and tags
  2. Use Git Branches: Create feature branches for major changes
  3. Monitor Build Logs: Check GitLab CI/CD logs if deployments fail
  4. Add interactivity: You can enhance Hugo with plugins that can automatically give your readers feedback mechanisms like email (https://fabform.io/a/hugo-contact-form/) or disqus-like comments (https://isso-comments.de/docs/)

Conclusion

You now have a professionally hosted blog with zero hosting costs! Hugo’s speed and simplicity, combined with GitLab’s robust CI/CD and free SSL certificates, make this setup perfect for personal blogs and small websites.

Remember to check Hugo’s and GitLab’s documentation for more advanced features and customizations. Happy blogging!

Related Posts

Simulating GitLab Activity

Simulating GitLab Activity

Self-hosted GitLab instances are critical infrastructure for many organizations. While setting up GitLab is straightforward, operating it at scale requires deep understanding of its behavior under real-world conditions. This is where user activity simulation can become invaluable.

Token-Zero: When you need a token to create a token

Token-Zero: When you need a token to create a token

When automating a GitLab installation, you’ll often need to create “token zero” - the first access token used to bootstrap your automation processes. Unlike the initial root password, this token is specifically scoped for API interactions during setup. This creates a chicken-and-egg situation: you need a token to make API calls, but you need to make an API call to create a token.

A New Blog

A New Blog

I’ve finally taken the plunge and committed to sharing my DevOps experiences through this new blog. After years of wrestling with pipelines, debugging deployment issues, and celebrating those sweet moments when everything just clicks, I figured it’s time to give something back to the community that has taught me so much. I’ll be sharing both the wins and the “learning opportunities” (aka the times things went spectacularly wrong) that come with working in DevOps.