Hello World!

Posted on Apr 23, 2023
tl;dr: Nothing fancy. Digital Ocean App hosting + basic theming.

I decided to start writing posts and was curious about what type of blog to start. As an engineer, I wanted the flexibility of Markdown, version control traceability, and automatic rollouts.

I chose Hugo for static website generation and, for now, Digital Ocean apps for serving pages. Later on, I'll migrate to AWS CloudFront.


Initially, I considered an interactive shell-like theme, but it would be too nerdy. So, I opted for Archie as the main theme, which provided a minimalistic, engineering-like blog style.

If you cloned your theme to a sub-path with git clone, don't forget to create a .gitmodules file; otherwise, the DO builder won't pull the theme from the target repository.

[submodule "themes/archie"]
  path = themes/archie
  url = https://github.com/athul/archie.git


DO apps offer an easy deployment process. A simple YAML file placed in .do/app.yaml provides everything needed to deploy a static app:

name: static-hugo
- build_command: rm -r ./public; hugo --destination ./public
  environment_slug: hugo
    branch: master
    deploy_on_push: true
    repo: kuzaxak/blog
  name: static-hugo

I bound the DNS to DO nameservers on the Namecheap main page. Remember to check that they're propagated, and you can continue with:

dig NS kuzaxak.dev

After creating a DO App, follow the wizard – it's self-explanatory. You'll get a DO subdomain. Attach your domain on the Settings page, and you'll automatically receive A records in your DNS zone.

Fine tuning

DO apps require default pages to be present in the final filesystem folder:

  • index.html
  • 404.html

Hugo creates index.html without any additional configuration.

404.html might be created by the theme, but not in my case. The theme's 404 was empty. Easily fix this by creating a layouts/404.html file. Copy your theme's index.html and add a helpful error message to guide people back or report a broken link.

Check that DO detects your content in the build log. It should look like this:

 static site output directory is not explicitly set, attempting to look for static files
[2023-04-23 11:47:52]       checking /workspace/_static: not found
[2023-04-23 11:47:52]       checking /workspace/dist: not found
[2023-04-23 11:47:52]       checking /workspace/public: found
[2023-04-23 11:47:52]    using document root /workspace/public
[2023-04-23 11:47:52]  
[2023-04-23 11:47:52]  => Uploading files to Spaces
[2023-04-23 11:47:52]      categories/index.html
[2023-04-23 11:47:52]      contact/index.html
[2023-04-23 11:47:52]      about/index.html
[2023-04-23 11:47:52]      404.html
[2023-04-23 11:47:52]      categories/feed.xml
[2023-04-23 11:47:52]      feed.xml
[2023-04-23 11:47:52]      index.html
[2023-04-23 11:47:52]      js/feather.min.js
[2023-04-23 11:47:52]      js/main.js
[2023-04-23 11:47:52]      js/themetoggle.js
[2023-04-23 11:47:52]      page/1/index.html
[2023-04-23 11:47:52]      robots.txt
[2023-04-23 11:47:52]      sitemap.xml
[2023-04-23 11:47:52]      tags/feed.xml
[2023-04-23 11:47:52]      tags/index.html
[2023-04-23 11:47:52]  
[2023-04-23 11:47:52]  => Configuring index document: index.html
[2023-04-23 11:47:52]  => Configuring error document: 404.html
[2023-04-23 11:47:52]  => Uploaded 34 files


Adding content is pretty easy. I recommend using date prefixes for the posts. This way, you can easily get a sorted list without introducing subfolders.

To automate date parsing from a new file name, create archetypes/posts.md with a parser regex:

title: "{{ replace (.Name | replaceRE "^[0-9]{4}-[0-9]{2}-[0-9]{2}-" "") "-" " " | title }}"
description: |
tags: []
date: {{ .Name | replaceRE "^([0-9]{4}-[0-9]{2}-[0-9]{2}).*" "$1" }}
slug: "{{ .Name | replaceRE "^[0-9]{4}-[0-9]{2}-[0-9]{2}-" "" }}"

Now, you'll be able to create your first page. I started with this article to practice writing.

hugo new posts/2023-04-23-hello-world.md


You're probably curious if anyone is actually reading your blog. To find out, you can add Google Analytics, which is supported by Hugo.

Register your website and prove ownership via DNS; after that, you'll receive a G-tag code.

Add it to your config.toml; mine looks like this:

relativeURLs = true
baseURL = "/"
languageCode = "en-us"
title = "Vladimir Kuznichenkov | Engineer"
author = "Vladimir Kuznichenkov"
theme = "archie"
copyright = "© Vladimir Kuznichenkov"

# get information about the Git repo, such as last commit to a file
enableGitInfo = true

# Code Highlight
pygmentsstyle = "monokai"
pygmentscodefences = true
pygmentscodefencesguesssyntax = true


googleAnalytics = 'G-MEASUREMENT_ID'
enableRobotsTXT = true

  mode = "toggle"
  author = "Vladimir Kuznichenkov"
  copyright = "@ Vladimir Kuznichenkov"
  WebMentionDomain = "kuzaxak.dev"
  mathjax = true # enable MathJax support
  katex = true # enable KaTeX support

# Social Tags
  name = "GitHub"
  icon = "github"
  url = "https://github.com/kuzaxak/blog"

  name = "Twitter"
  icon = "twitter"
  url = "https://twitter.com/kuzaxak/"

  posts = "/posts/:year/:month/:day/:slug/"
  tags = "/tags/:title/"

  mediatype = "application/rss"
  baseName = "feed"

    typographer = false
    # allow inline HTML, such as spoiler warnings
    unsafe = true
  startLevel = 1
  endLevel = 6
  ordered = false

    identifier = "blog"
    name = "./blog"
    url = "/posts"
    weight = 2
    identifier = "about"
    name = "./about"
    url = "/about"
    weight = 3

    name = "Tags"
    url = "/tags"
    weight = 4

  changefreq = 'monthly'
  filename = 'sitemap.xml'
  priority = 0.5