TLDR
After a few server crashes, I rebuilt the site with Hugo, recreate a CICD pipeline and deployed it on statically on AWS.
Why am I doing this… Again?
It had been a little more than a year ago since I made the site. When I first started building it, I wanted to have as much customisability as possible.
I learnt a lot and had great fun doing it… but recently, it felt like I was using a chainsaw as my kitchen knife.
The setup was complicated, the cost was not low and I found no place to use the flexibility I initially prepared for.
The last straw that broke the camel’s back was that my t2 micro server just dies whenever I try to implement new stuff and building it with NPM on the server… With CPU traffic reaching 100%, so is my patience with the current setup.
To break down my requirements:
- A mechanic that can convert Markdown files (used for writing the README on Github or Obsidian) into formatted HTML
- A CI/CD pipeline that allows me to push to publish
- Static pages that support code snippets, image placement and good readability
- As few $$$$ as possible
I recognise that my need for dynamic sites only existed due to the way I implemented the website.
So after a while of research for multiple factors and referencing other setup, I set my eyes on Hugo and Static Hosting on S3 Buckets.
Here is a quick architecture diagram
Developing the Site
What is Hugo
Hugo is designed to generate static website with emphasis on speed and flexibility. With its native support to render md to HTML and vast library of templates available, it was a logical decision to reimplement the blog in Hugo.
I went with the PaperMod template as it best fits the mood I want for my blog post.
The configuration is not difficult as it relies on YAML files to define variables for the site. You can easily get it set up following their documentation:
https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-installation/
Some tips I wish I knew
1. Layout Customisation
I came to notice that I have weird fixation on the most useless details. Fortunately, Hugo and PaperMod support customisation to have things setup my way.
One great thing about this tech stack choice is that it is easy enough to adjust layouts on top of their template with some basic HTML and JavaScript knowledge.
For example, to move the tags that should be on the bottom of the page to the top of the page:
- Copy the single.html file from
themes/layouts/_default
to thetheme/_default
directory - Edit the HTML file like your standard HTML file, you can add styling options, some small JS script to adjust the layout to your liking
Similar flow goes for creating a new layout type:
- Create a new layout within
themes/_default
- start with copying existing layout and remove parts you don’t need
- Naming of the file is important as it is used to pair your md file with the layout
2. Why is my layout broken when I pull the repo to other computer?
The layouts is linked to your project using the git submodule
.
By using submodule, it allows us to attach other projects as a subdirectory. This ensures that project can easily fetched and updated to new changes.
When github repo is pulled by a new computer, the themes subdirectory is not pulled automatically. Hence you will need to run:
git submodule update --recursive
3. Relative or absolute path when customising?
I had some confusion about this issue on customised scripts before deployment as I didn’t have the big picture back then.
With the site being online now, given the choice between
images/something.png
andhttp://fake.website/images/something.png
I will definitely recommend doing it with option 1: relative path all the way.
To be brief, this is to do with having BASE_URL defined in github action and your control over where the image files will be by the end of the deployment. For this advice to be valid, please reference to it in combination with the Finding a way to use images not built with Hugo part of the blog.
Deploying the Site
The task was extremely daunting as it requires setup of multiple services across two providers - AWS and GitHub.
Luckily, the internet never lacks amazing content like this: https://www.jeromethibaud.com/en/blog/deploy-hugo-site-to-s3/
By following this guide, I had no issue getting the site online. I already had my domain on Route53 in my previous setup so its even easier for me.
Where I Diverge from the guide
1. Finding a way to use images not built with Hugo
I had a weird setup where different image will be rendered in dark-mode and light-mode. This wasn’t working as one of the image is not referenced during build.
To fix this, I added the following line in the main.yml to force Github Action to slip the file into the built folder for me:
run: |
hugo \
--minify \
--baseURL "${{ vars.SITE_BASE_URL }}/"
+++++++++++++++++++++++++++++++++++++++++
- name: Copy Core Image
run: cp images/* ./public/images
+++++++++++++++++++++++++++++++++++++++++
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4.3.1
The thing works like a charm afterwards!
2. Hiding my S3 behind CloudFront CDN
After I done the setup, I wanted to further reduce my attack surface and S3 public access stood out like a sore thumb to me.
To adjust this, I did some minor adjustment ot the setup so that the content can be served even when S3 bucket is configured to be private:
Change the distribution origin to the s3 endpoint
Enable Origin Access Identity for CloudFront
Copy the policy to Bucket Policy in S3
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<insert-your-bucket-name-here>/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<your-id>:distribution/<your-distribution-id>"
}
}
}
]
}
- Remove the available to public setting and turned off the static hosting configuration
Doing this should make the S3 endpoint no longer reachable by others directly and actualising the setup on the diagram.
Thank you for reading! If you want to share any thoughts with me, please feel free to connect with me on LinkedIn and stay tuned for my next post!