Jason Smith
•January 25, 2024
I finally did it! It took me a year but I moved my site from WordPress to Hugo and then hosted it on Cloud Run. It has been a journey and I want to share it with you.
Way way back in the day, I was introduced WordPress. My memory is a bit rusty but I started using it as a Content Management System (CMS) around 2007/8. I was young and working on my small business and this made web design easy. CMSs weren’t necessarily a new concept back then but WordPress changed the game. In fact, per W3Techs, WordPress is used by around 43% of all websites today!
It was (and still is) Open Source and was relatively easy to use. It was also extensible and easy to customize. I think this is what heavily contributed to it’s adoption. In a lot of ways, you can consider it the “Linux of CMSs”. This, of course, made me an instant fan. Over the years, I made dozens of sites using WordPress.
When I decided to build my professional site back in late 2019, I decided to use what I knew and at the time, WordPress was the answer. After all, I had collaborated on many WordPress sites for myself and others over the years. It would be a really easy lift and I could extend it as needed.
I decided to host my website on Kinsta. For one, they had really great reviews. They are also an enthusiastic Google Cloud Customer. I want to say that regardless of my migration, Kinsta is an amazing service. They were very easy to use, had an incredibly reliable service, and an amazing support team. If you are a power WordPress user, I highly recommend them. However, I began to re-evaluate my need for WordPress.
One of the big things was the unneccesary complexity of WordPress for my use case. I was hosting a simple blog with only one contributor, myself. It wasn’t a complex application that had a team supporting. I found that the backend was a bit more than what I actually needed for my personal website.
Another issue was cost. While WordPress is open source and therefore technically free, hosting it has various costs associated with it. Way back in the day, I would just toss it on one of my VMs and call it a day. However, it also meant that I had to maintain uptime, security patches on the server, configurations, etc. While I could do it, I would rather let someone else shoulder the responsibility. Kinsta, again, is an absolutely fantastic service and I would recommend them to anyone looking to host a WordPress site. While $30/month isn’t really breaking the bank, it did seem like more than I needed.
I began to wonder if static webpages would be a better fit for my use case instead of using a CMS.
I had heard a lot about Static Site Generators for a while. They essentially take Markdown and other assets like CSS, Javascript and images and generate a static HTML website that can be hosted virtually anywhere. While there are numerous options, each with their own pros and cons, I chose to go with Hugo. Some people may be wondering why I chose Hugo over Jekyll, one of the most popular static site generators. I am personally not a huge fan of Ruby which is why I didn’t go with Jekyll (GoLang for the win!).
I am also a HUGE fan of Google’s Cloud Run. I mean, come on, serverless containers. I love the idea of containerizing my application and then having it scale down to zero when no one is browsing. In theory, I can get away with spending WAY less than $30/month to host my blog.
I tried to convert my site from WordPress to Hugo using a variety of plugins and I just couldn’t make it happen. I tried to design something myself but I have the graphic design skills of a sea sponge so I finally just broke down and hired someone to do the design. They rewrote the site from scratch using TailwindCSS and of course Hugo.
Once he turned over the assets, it was time for me to containerize it. I am going to do you all a solid and share with you the Dockerfile that I used if you want to do it yourself. Sorry, this blog post won’t talk about building a site in Hugo as, well, I couldn’t figure it out for myself. Fiverr was a great resource for me to find an expert to do it for me.
# Stage 1
# Use the base image 'ubuntu:noble'
FROM ubuntu:noble as hugo
# Update the package repository
# Install necessary packages
RUN apt-get update && \
apt-get install -y \
ca-certificates \
wget && \
update-ca-certificates
# Define the Hugo version
ARG HUGO_VERSION="0.121.2"
# Download and install Hugo
RUN wget --quiet "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz" && \
tar xzf hugo_${HUGO_VERSION}_Linux-64bit.tar.gz && \
rm -r hugo_${HUGO_VERSION}_Linux-64bit.tar.gz && \
mv hugo /usr/bin && \
chmod 755 /usr/bin/hugo
WORKDIR /opt/HugoApp
# Copy Hugo config into the container Workdir.
COPY . .
# Run Hugo in the Workdir to generate HTML.
RUN hugo
# Stage 2
FROM nginx:1.25.3-alpine3.18-slim
# Set workdir to the NGINX default dir.
WORKDIR /usr/share/nginx/html
# Copy HTML from previous build into the Workdir.
COPY --from=hugo /opt/HugoApp/public .
# new nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY ./extras/nginx.conf /etc/nginx/conf.d/default.conf
# Change file permissions for site
RUN chmod 755 -R /usr/share/nginx/html
# Expose port 80
EXPOSE 80/tcp
You will notice that I have a custom nginx.conf in there. This is just a custom nginx file to handle some redirects and other things. You can create your own and then store it in an extras folder in your project’s root directoy (or wherever you choose to store it).You can remove the following lines if you want to use the default nginx.conf in the file.
# new nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY ./extras/nginx.conf /etc/nginx/conf.d/default.conf
Now, in order to build this container, you need to have this Dockerfile in the root of your Hugo project directory. Then simply run docker build -t hugoapp .
replacing “hugoapp” with whatever you opt to name your container image and you are good to go.
Once my container was built, I then pushed it to Google Artifact Registry and then deployed it to Cloud Run. Now obviously I wanted to use my own domain name so I setup a Global Load Balancer with Cloud CDN enabled.
Now you may be asking why I didn’t use the Firebase Hosting preview or map a custom domain. After all, they would be cheaper than a GCLB, especially for a simple static website. Well, using GCLB is the best practice for an enterprise serverless application. Yes, a Hugo site is not an enterprise application, but I am leading by example.
I also have other plans for GCLB beyond this one site so there’s that. For example, I needed to setup some redirects and do some other routing to help with broken permalinks.
Now I have my blog containerized and running entirely on Google Cloud. Technically, it was running on Google Cloud before via Kinsta, but now it’s in my own Google Cloud project. There are a few more things I want to do with the design so you may see a few tweaks here and there. I also want to setup GitOps for my posts. I will be using pipelines and containers as my CMS (and will blog about it) but for now, I am happy with the results.