how I built my blog site

With the release of my first blogpost on this new site, I also wanted to do a quick writeup on what I did to build it! This setup is heavily inspired by NetworkChuck’s Obsidian + Hugo video, as this was perfect for my use, so definitely consider checking out his video too!

Tooling

My blogpost workflow revolves around two amazing tools:

  • Obsidian is a markdown-based note-taking tool meant to link ideas and notes. I use Obsidian for absolutely everything and have full intentions on sharing my Obsidian system in the future!
  • Hugo is a free, open-source static website generator known for its ease of use and configurability. The plan is any content written in Obsidian can easily be copied into Hugo and displayed as a separate blogpost.

Generating a Hugo Website

Start by installing Hugo from the official installation page and install it based on your platform. I’m using macOS for everything, but the command should be the same.

In a terminal, navigate to the directory where you want to store your website, and type:

hugo new site blog

Replacing blog with whatever you’d like to name the directory.

To make things pretty, I selected the Hugo Blog Awesome theme at the time of writing. There are many other themes available, so feel free to select your own and install it following the instructions addressed by the selected theme.

To test the website, type:

hugo server

Then navigate to localhost:1313 in a web browser, or whatever is displayed by the server. I won’t go into the hyper specifics of everything, but if you’d like to learn a lot more about the website building process and how Hugo works, definitely consider looking at NetworkChuck’s video and the Hugo documentation.

Generating A Blogpost

Markdown Front Matter

Front matter is a section at the top of markdown files that contains metadata, like the title and author, which tools like Hugo use to organize content. I use markdown front matter for both my Obsidian notes and my Hugo blogposts, as it allows me to extract various features for each tool. Here’s a quick image of my blogpost note front matter:

Pasted image 20250113203959.png

The goal and status fields are for my Obsidian system.

  • The status field indicates if a note is active, which determines whether or not it show up on my central Obsidian dashboard.
  • The goal field provides a quick summary of what the note is about and what I want to achieve with it.

The title, description, author, and date fields are for my Hugo website.

  • The title field is the actual title of any blogpost that shows up on my website. Unlike Obsidian, Hugo does not use file names as titles.
  • The description field is for additional information about the blogpost, which shows up in some web previews or embeds.
  • The author field indicates who wrote the blogpost (is permanently me, hun).
  • The date field indicates when a blogpost was published. This shows up on the website when navigating the posts I’ve made.

Migrating Content

With this simple system, I can theoretically migrate blogposts written in Obsidian into my Hugo site and it’ll simply work! While this is mostly true, one small issue comes with how Obsidian and Hugo handle images.

Obsidian embeds images in a specific way. For a photo called filename.png, Obsidian handles it like this:

![[filename.png]]

These referenced images are stored in a single directory by default. To export a blogpost with images, you’ll need to navigate to Obsidian’s images directory, locate the file (likely out of a large number of files), and move it into Hugo’s structure, repeating the process for each image individually.

Even after exporting the images properly, making things slightly more challenging, Hugo embeds images in a different way. For the same photo called filename.png, Hugo handles it like this:

![filename](</images/filename.png>)

Note: The /images/filename.png path is a requirement if images are stored within the /static/images directory within Hugo. Furthermore, the <> around the file path ensures that it’s still properly handled if there’s a space in it.

This means after the blogpost and images have been copied from Obsidian and into Hugo, the resulting blogpost must be altered to accommodate Hugo’s syntax.

My Handy Export Script

Depending on the length of the blogpost, the number of images referenced in it, and the directory structures of both Hugo and Obsidian, this process can become extremely complicated and time-consuming very quickly. To solve this problem, I’ve created a little python script that automates the entire process! Feel free to download it here on my GitHub.

In a nutshell, the script does the following:

  • Finds active blogs: Navigates to your Obsidian blog directory and checks the front matter of each file, looking for status: active.
  • Copies blog into Hugo: Once an active blog is found, the script asks what blog to copy the blogpost to. This will list the available directories in the /content/posts directory in Hugo.
  • Collects images: The script parses every instance of an image in the active blog, looking for the ![[]] syntax that Obsidian uses to reference images.
  • Copies images into Hugo: It then navigates to the Obsidian image directory and copies the referenced images into the /static/images directory in Hugo.
  • Pushes to GitHub: Lastly, the entire blog repo is updated and pushed to GitHub, with the option to submit your own git commit message.

Feel free to use the script! It only requires five explicit paths:

  • Obsidian blogs
  • Obsidian images
  • Hugo blogs
  • Hugo images
  • GitHub repo path (the created Hugo website directory)

Furthermore, this also assumes that the status field within the Obsidian front matter is in use, so feel free to implement that front matter or modify the script in any way!

Publishing Content

To make my website and published blogs available on the internet, I’ve created a GitHub repository for my blog and linked it to Cloudflare Pages. A worker monitors the repository for updates, and when one is detected, it rebuilds and restarts the Hugo server almost instantly.

This method is fantastic because it’s completely free, and you also benefit from the network protection mechanisms that Cloudflare offers. I did purchase the hunio.org domain name and linked it to my Cloudflare Pages setup, but many domains are available for very low prices.

Hopefully that provides some insight on how I used these tools to create this little website! :)

References