I switched this blog from Jekyll to Hugo

My experience as a noob of web development

Posted by Giulio Magnifico on Saturday, August 3, 2024
jekyll-to-hugo

Maybe you haven’t noticed it, but this blog is a bit different now, this because the ‘engine’ behind it, now it’s Hugo instead of Jekyll.

But before getting into the details, an important disclaimer: I absolutely don’t have in-depth knowledge of the web development. Surely some expert will notice that what I wrote could have been done better and/or in some other way, but now I have already done all in this way, but if you have suggestions, they’re welcome!

So, I simply want to tell the story of someone (me) with basic web skills who wants to open their own site (hosted on a private VPS) quickly and easily for a few dollars a month ($7).

It all started because I wanted something simpler and more immediate for writing a post, refresh the blog with a more modern look, improve its structure, and add the ability to use drafts.

So, on the first attempt, I looked for a CMS that would act as the backend of the site with Jekyll, but since I don’t use GitHub in my workflow (and don’t want to use it), I didn’t find any CMS that integrated well with Jekyll. The only one that really worked well was the Jekyll Admin plugin, which would be perfect to use for testing, but it is almost unusable on a production site, as it requires always having a page to log in from. Moreover, I don’t remember exactly what the problem was or were, but it was something related to the technical aspects of the VPS.

So I decided to discard the idea and directly use something better integrated. My first choice was Ghost because, at first glance, it seemed simple and effective.

Ghost

I opted to buy another DigitalOcean droplet in order to make the tests, the base one with NVMe storage and 25GB of storage (7€/month).

hugo-droplet

And another domain (I’m using Hover usually for that) because my initial plan was also to change the domain, so I bought ‘giuliomagnifico.xyz’.

domains

Then I used the official guide to install it, and on 30/40 minutes the site was up and running (apart from some issues with the MySQL login/account).

However, after a short time spent with Ghost, I noticed that it was almost completely saturating the 1GB RAM of the VPS, without even a post, and I didn’t want to increase the RAM of the VPS and pay more. Especially because after a little Hugo usage, I discovered that it’s too focused on monetization, on controlling how much money is earned from a page, the user engagement, (paid) subscriptions, sales and so on… and, since none of these features interest me, it seemed absurd to pay for more RAM on the VPS for things I would never use. Additionally, after encountering several issues with MySQL, I lost the motivation to use a database and decided to stick with a static site instead.

So I ditched Ghost and switched to trying Hugo.

Hugo

I reset the DigitalOcean droplet and started over with Hugo following the official guides.

After installing it, I found myself quite confused because the structure of the backend, the folders, and files was quite different from Jekyll, I’d say more complex but not necessarily worse. But I quickly realized how fast and powerful it was, it took less than a second to rebuild the entire site (even though it was still empty).

Hugo-compiling So I tried to understand its structure better. Below is a comparison of the structure of this website: Jekyll on the left, Hugo on the right.

layouts

To better understand how everything worked, I searched for a theme with a decent appearance to practice with.

There are many cool themes on the Hugo site, but I immediately chose the Clean White Theme for Hugo because I found it nice and well-suited to my needs. Installing it was straightforward by following the instructions, but I didn’t fully understand how or why it worked until I began modifying it to fit my needs. These steps helped me gain a better understanding of how Hugo works and how it differs from Jekyll.

the differences I found

The biggest difference I understood is that, while in Jekyll you make changes directly to the folders and files in the main directory, and Jekyll ignores the folders that start with an ‘underscore’, with Hugo you make changes only inside the folder of your current theme, and then by recompiling the site, the changes are “executed” on the folders and files inside the public part of the site.

Additionally, the structure of the URLs linking to each article is much simpler and more convenient, instead of being:

  • domain/category/year/month/day/post-name.html

Example: https://giuliomagnifico.blog/home/2024/07/08/home-setup-v5.html

It becomes:

  • domain/post/post-name/

Example: https://giuliomagnifico.blog/post/2024-07-08-home-setup-v5/

Another difference is the organization of categories: since the category name is no longer included in the URL, changing a post’s category doesn’t affect the URL scheme.

Whereas with Jekyll, it happened to me several times that when I changed the category of a post, the URL of that post changed as well, and if there was an old link online, the page was no longer reachable (and it was necessary to set up a redirect on Nginx). Quite annoying.

Speed: Hugo is faster than Jekyll, both in rendering pages on the browser and building the site. Jekyll took 5-6 seconds for compilation, now Hugo (with the same posts and images) takes 2-3 seconds.

Hugo-compiling2

As for the speed of the site, it seems much faster to me, but you have to tell this to me :)

the transition from Jekyll to Hugo

I felt bad about the idea of transitioning from one platform to the other because I always think that I’ve covered everything and I’m almost sure that it will all work fine after the transition. In practice, though, a lot of things ended up broken and i have no idea where to start debugging.

Convert the articles

I began by formatting each post. The text was already in Markdown, so the content remained the same, but there are slight differences between Hugo and Jekyll in the opening (the ‘Front Matter’) f each post.

For Jekyll, the opening of the post is:

---
layout: post
title: "A nice title"
subtitle: “and the subtitle”
categories: xxx, yyy, zzz
author: Giulio Magnifico
---

And the date of the post is ‘pulled’ from the title of the post, which must be:

2023-01-31-title.md

In contrast, for Hugo, the date in the title isn’t important or necessary, as the Front Matter includes the date:

---
layout: post
title:      "Title"
subtitle:   "Subtitle"
#description: ""
date:       2024-04-10
author: "Giulio Magnifico"
#image: "/custom-background.jpg"
published: true #or draft
tags: ["tag1", "tag2"]
categories: [ "category" ]
---

So, I had to take the Front Matter of each old article and modify it to make it compatible with Hugo. It was a bit time-consuming, but I did it, and I kept the date in the title because it makes it much easier and more organized to find a post.

Then, I just needed to move all the *.md files into the /content/post/ folder and rebuild the site to see them appear.

Images

I decided to keep the folder name the same for the images so that the URL remained unchanged. By simply moving the folder with the images from Jekyll to Hugo in /etcetera/content/_images, the URL remained the same and the images were already visible.

Jekyll: https://giuliomagnifico.blog/_images/2024/article-name/image.jpg

Hugo: https://giuliomagnifico.blog/_images/2024/article-name/image.jpg

Comments

For the comments (since this is a static site), it’s necessary to use an external service with a database. The Hugo theme I had chosen included an option to enable comments with Disqus, but since Disqus is a privacy nightmare, I opted not to use it. For the Jekyll blog, I had already chosen the excellent FastComments service, which, for €0.99 per month, allows me to have comments managed by them and ensures full GDPR and privacy compliance.

I thought it would be enough to re-insert the comment script in the post layout to get the comments back… but I was wrong. Since the URLs of each post were changed, the comments were no longer visible in the post with the new URL. But fortunately FastComments provides several tools, including one to migrate the comments from one URL to another.

And so I did for the posts with comments:

fastcomment-migration

URL post

Unfortunately, this was a big problem because the URLs of the old posts were different from the new ones.

Example:

  • from this: baseurl/home/2024/07/08/home-setup-v5.html
  • to this: baseurl/post/2024-07-08-home-setup-v5/

So, I decided to create a redirect on Nginx for each old URL, pointing to the new one. It was quite frustrating to write all those redirects…

###### Redirect old blog URLs
    # Redirect www to non-www
    if ($host = 'www.giuliomagnifico.blog') {
        return 301 http://giuliomagnifico.blog$request_uri;
    }

    # Redirect old blog page
    location = /home/2024/07/08/home-setup-v5.html {
        return 301 https://giuliomagnifico.blog/post/2024-07-08-home-setup-v5/;
    }
    # Redirect old blog page
    location = /networking/2023/01/05/home-network_v4.html {
        return 301 https://giuliomagnifico.blog/post/2023-01-05-home-network_v4/;
    }
    # Redirect old blog page
    location = /misc/2023/07/22/I-found-a-IT-job-thanks-to-this-blog.html {
        return 301 https://giuliomagnifico.blog/post/2023-07-22-i-found-a-it-job-thanks-to-this-blog/;
    }
    # Redirect old blog page
    location = /tips/2022/09/25/macos-wallpaper-huge-cache.html {
        return 301 https://giuliomagnifico.blog/post/2022-09-25-macos-wallpaper-huge-cache/;
    }    

    and so on for about 50 posts...

Analytics

For the analytics, I use Umami, which is a free analytics service if hosted on your own server (like I do), or paid if you use their cloud service.

The transition was very simple: just moved the script with the unique ID from Jekyll to Hugo, and the analytics started working again as before, but with the new site.

umami

Out of curiosity: I host Umami on another instance of DigitalOcean, a basic droplet ($6/mo), on the subdomain umami.giuliomagnifico.blog.

umami-droplet

End of migration

At this point, everything was back to normal and now, if there’s still an old URL somewhere online, it’s automatically redirected to the new one. Try opening this link created by Jekyll with its original scheme: https://giuliomagnifico.blog/tips/2022/09/25/macos-wallpaper-huge-cache.html

Improvements and new features

As you can see, compared to the original Clean White Theme for Hugo, this website is a bit different because I modified the theme to suit my preferences. Fortunately, the theme already included search functionality with Algolia, so I created an account and configured the layout’s code to work the way I wanted.

To be honest, the original theme only allowed the search function to work within the post title, but I made some adjustments and managed to have Algolia index the entire content of each post. So now the search is ‘universal,’ and when you search for a word, it gets highlighted. If you want to try it out, just go to the Search page and test it.

search

Tips

I’m using a few small tricks to speed up my workflow,one of them is using some shell aliases:

alias alg='npm run algolia'
alias h='hugo'
alias hd='hugo --buildDrafts'

Another tip concerns Algolia search. The search function requires manually updating the indexing file by running npm run algolia. This should be done every time there is a change in the text of any post in order for the changes to be reflected in the Algolia index on the server. Since I’m sure I will consistently forget to do this, I have automated the process with crontab:

0 3 * * * cd /home/hugo/etcetera && npm run algolia

Conclusions

As I mentioned before, I know very little about web development, but I wanted to start this blog to share my experiences, hoping it might help or at least inspire others guy online. Without any pretensions.

From my point of view, if you’re starting a new, somewhat complex project or site, I would recommend going directly with Hugo, even though it’s slightly more complex. Jekyll is okay, easy to set up and use, but you might encounter some limitations as soon as you need additional features.

The next step will be to integrate it with a CMS to post more easily. But for now, being able to use drafts makes it very easy for me to write even from my iPhone: I use a markdown editor synchronized in the Cloud One Markdown and then keep the post published as a “draft” using the draft: true option in Front Matter.

After, I build Hugo using hugo --buildDrafts

Then, by using the command hugo list drafts, I can see the URL and open the page as if it were published. For example, this post was a draft before being published:

root@hugo:/home/hugo/etcetera#  hugo list drafts
path,slug,title,date,expiryDate,publishDate,draft,permalink,kind,section
content/post/2024-08-03_from-jekyll-to-hugo.md,,I switched this blog from Jekyll to Hugo,0001-01-01T00:00:00Z,0001-01-01T00:00:00Z,0001-01-01T00:00:00Z,true,https://giuliomagnifico.blog/post/2024-08-03_from-jekyll-to-hugo/

In the end, when I see everything’s okay, I turn the draft into a regular post, and it shows up here.

P.S. I decided not to use the .xyz domain because everyone told me it’s used for online scams and porn sites. Too bad, I liked it!

P.P.S. If you were subscribed to the RSS feed, you need to update the URL. The link is at the bottom of every page.