How to build and host a static website in one weekend?
Hi there!
Is it possible to build a personal website in one weekend? Short answer: yes. As my first post to kick it all off, I thought it would be great to deep dive on this topic. There are a lot of related posts out there, but most were vague at best and overlooked the less popular but important bits. Let’s firstly discuss on why should you build your website.
My reasons for a personal website
Here are the highlights:
- I have always wanted to pen my thoughts and share my knowledge, and a personal blog is the perfect platform to do so.
- English isn’t my native, so translating my thoughts is also the perfect way to improve my writing and storytelling skills.
- There is no limitation, censorship, or other boundaries on a personal page. A red-tape free zone where anything goes!
A pure static website
Let’s get down to business. I’ve decided to go with the most basic and lean solution - a static website. Why so? Firstly, it’s easy, cheap, and perfectly fulfils the most basic needs. Secondly, static websites are well indexed by search engines. Lastly, it’s quick and painless - I’ve only spent a couple of hours building and hosting the website. Once I understood that a complex solution is not required, I searched for the perfect fit. The criteria was pretty simple:
- It should be a quick way to start with content creation – no time should be wasted configuring some cumbersome CMS
- A static website is cheap and an easy way to host a solution. Not necessary to spin up any complex infrastructure.
- Well-known formatting language, preferably markdown
There are many articles about what engine to choose for a static website, e.g. techradar or review of top-5 static site generators. I read up on a couple of articles and quickly made my decision – I swiped right on Hugo.
The next important decision is how to host the website. The answer was obvious - AWS S3 Static website hosting. There are tons of online guides about how to configure static website hosting on S3, and I’ve relied on aws official guideline. That was a straightforward step, and I was able to access the website via the S3 website endpoint.
DNS Delegation
Lastly, it’s required to move your domain DNS under Route 53 management. This was a tiny challenge from GoDaddy. I started with the creation of a public-hosted zone for my domain. A newly created hosted zone has NS records with 4 DNS servers, that supposed to be populated on the GoDaddy console to delegate domain management to Route 53. I updated records set per official gulde lines. Waited for 2 days… And nothing. Then I tried again. And zero, zip, zilch, nada!
Thus, I delved into the Humankind’s most sacred knowledge source – StackOverflow. No surprises, there were tons of similar issues, and the root cause of the problem is GoDaddy’s care of end-users - they’ve locked changes for DNS for only ‘experienced users’. Thus, I should have consciously enabled it. Fine, I did it.
Once I was able to delegate DNS management to Route 53, I was able to configure two ‘A’ records to resolve my domain name S3 stored website.
Important Note
If you are using other services from GoDaddy, e.g. their SMTP for a mailbox on your domain, don’t forget to copy (or export/import) other DNS records
SSL Certificate installation with CloudFront
The last step of the process is the installation of an SSL certificate. I wasn’t keen to introduce a compute level, thus I leveraged CloudFront for encryption. To issue a certificate, I decided to use Let’s encrypt which is a pretty famous certificate authority (CA). The main advantage of Let’s Encrypt is that their certificates are free, and it’s not required to pay extra to AWS. But there is a small caveat - any Let’s Encrypt certificate is only valid for three months. So the certificate has to be re-issued and re-deployed every three months, but this should be an easy task to automate.
There is a brilliant instruction on how to issue a certificate through certbot (a Let’s Encrypt tool to work with certificates) and to install it in your CloudFront distribution.
Important Note
If you followed the above notes, you should be able to disable bucket policy during certbot execution. I achieved it by the most common IT technique – copy/pasting the policy. Down the road, I’m going to modify the policy and set up a GitHub action to renew the certificate.
There is a couple of minor caveats missing in the above guide about the configuration of CloudFront distribution:
- Alternate domain name (CNAME) should be specified for your CloudFront distribution
- Custom SSL certificate has to be selected (it will be available in the drop-down menu)
- Default root object has to be specified as index.html
Once you’ve completed the above steps, it’s time for a cup of coffee or beer – whatever floats your boat – because it will take from five to thirty minutes for CloudFront to deploy your website to edge locations around the World. Once the distribution has been deployed, I tested the website and realized that links were broken. One more step was required.
Additional configuration for Hugo to fix broken links
II realised that I’m not the only person puzzled by this unexpected behavior. The root cause of the problem is pretty straightforward - Hugo does not add ‘index.html’ (a direct reference to a page) at the end of the URL. There are multiple ways to solve this issue such as redirect rule on S3, redirect via web server, or Lambda Edge.
I decided to have a look at the issue from an application point of view. After a quick investigation, I realized that a few people faced with a similar problem. This article has a pretty detailed explanation on how to configure your static distribution to fix the above issue.
I quickly applied the above configuration locally and deployed it in AWS. Surprisingly, the issue still was there. But I quickly realized that I had yet to update the CloudFront cache. After cache invalidation, the website was up and running without any issues.
Future improvements
It’s not a complete solution, but it’s a start. Down the road, I’m going to introduce a few minor items:
- Setup GitHub actions to renew the certificate (I’m about to use Let’s encrypt for that)
- Automate my manual process of uploading updated files into the S3 bucket, i.e. update a website on ‘git push’.
- Allow bucket access through CloudFront only, i.e. configure OAI properly.
Stay tuned!