Hugo framework generates HTML files that load really fast. It does not have. As a drawback the developer needs to be more creative with some essential functionalities such as site search and sending contact forms.
Here you can visit the root url of my backend API: api.mikaelahonen.com .
Do you need a backend for Hugo website?
Building a fully static website without server side capabilities proved to be a difficult task. So I decided to create a simple and cheap solution to perform the needed tasks.
My Hugo website backend is not very busy at the moment. But it enables lots of cool stuff if I decide to create an app like
my-cool-app.mikaelahonen.com in the future.
Here are some use cases where I did and did not need the backend for Hugo.
Contact form - In the Hugo backend
The contact form in the browser calls the backend API and proxies the request to a transactional email service.
Comments - Partly in the Hugo backend
Users can send comments to my email through the backend.
I add the comments to Hugo data files manually and they will be rendered to the website on next deployment.
You can explore the commenting section at the bottom of this page.
Decision of moving around 100 comments from my old Wordpress website was easy. On the contrart I pondered a long time whether I will create the functionality for new comments in the Hugo website after realizing it would take significant effor.
The email approach
Page load in the statistics - Backend might be needed
Page load tracking runs in an external service at the moment.
The self built backend might be needed if ad blockers block the current service.
Site search - No backend
I configured Hugo to generate a json file containing the title and content summaries per post.
The search page in the frontend requests the static json file from the Hugo server.
Hugo backend hosting alternatives
The HTML files generated by my Hugo website are served from a managed service with limited configuration.
Similar managed services might provide something like “functions” to execute small scripts on their infrastructure. This would be quite cost efficient way to create a backend for a static website. I did not want to choose any vendor specific solutions.
One option would be to use my own virtual machine to host Hugo. I could serve the HTML files from one port and the backend API from another. It would be fully customizable but the deployment pipeline, setup process, failure management, SSL certificates and CDN would be a nightmare for such low visitor numbers.
My choice for Hugo backend hosting: Cloud Run in Google Cloud
I ended up hosting the minimal backend on serverless Cloud Run service in Google Cloud.
Cloud Run makes it possible to run a Docker image as a web service. This means that the backend can be migrated to any service that runs Docker containers with the same prinicples.
If you have a database, it should be in the same data center with backend service to minimize the costs from data transfer. I already had a
PostgreSQL database and some small apps running in Google Cloud for hobby projects, so it made sense to use the same provider for the Hugo website backend.
Google Cloud Run billing is based on instance size and actual usage. The costs per month will be only cents for my whole account. It’s great setup for multiple apps that receive requests infrequently.
Some alternatives for Google Cloud Run would be Scaleway, Vultr, Digital Ocean, CloudFlare, Vercel and many others. The keywords are serverless, containers as a service and web functions.
Python FastAPI for Hugo backend
To be more specific, my backend is an HTTP REST API:
- API is an umbrella term for communication between two services or frameworks
- REST is an API architecture
- HTTP is the web communication protocol
I have implemented the HTTP REST API on my website backend with a Python library called
FastAPI. FastAPI application is packaged in a Docker image which then runs as a container in Google Cloud Run.
I have experience from the other well known Python web framework
Flask. For a website backend receiving a few requests every now and then the performance is not an issue for either of them.
However, it is a well known fact that FastAPI is more performant than Flask without significant drawbacks. So why not use the better option?