My first attempt at using a static-site generator results in the blog you're reading now
I've been meaning to do a blog for a while now. I've been writing since I was a kid, and I've been wanting to put together a platform to share it. I didn't want to get distracted by technology choices, which had been an obstacle in the past so I kept it simple.
I didn't think much of it, but my brother noted that the tech sounded pretty cool and others might enjoy the details. This is a tech blog, so I guess it makes sense to share that story here, as meta as that may be.
Table of Contents
Planning / Design
There were a few decisions I made up front. Here's how I got there.
To DB, or not to DB...
As I said before, I wanted to keep things simple. I wasn't sure I wanted a database, and I live in a terminal window, so a fancy WYSIWYG editor is usually more frustrating than helpful to me. With all that in mind, I decided I'd like to write my posts in markdown.
Since I was going to be doing markdown posts in plain text, I started considering ditching the database altogether.
- Don't need an "admin" page
- Don't care for comments (enough spam and troll fodder out there already, IMO)
- Because of 1 & 2, no need for an authentication system. Fewer things to store, as well
- Posts will be in markdown, so no need to save them with any style info
- But what about the post metdata?? Dates, categories, etc.??
So I started thinking "Jeeze, without a database I'll have to come up with some system for embedding and then parsing the metadata for my posts within each post..." The I discovered frontmatter.
Luckily, the Jekyl creators came up with Frontmatter to server this purpose. Frontmatter is a section of YAML at the beginning of the Markdown file describing the metadata. It's parsed by the site's metadata parser and ignored by the markdown parser. Here's a sample:
--- title: This Blog date: 2017-07-20 21:10:46 categories: - Coding tags: - NodeJs ---
So that solved it! No database!
For the framework there were a lot of choices. I had narrowed it down to a flat-file system, which helped.
I also decided that I didn't want a dynamic backend. I've been meaning to do something with this constraint for a while, so I decided on a site generator that would compile down to html, css, and js. This would greatly simplify hosting.
Unfortunately it didn't work out. I ran into too many issues and found the documentation to be a little incomplete. There were too many different libraries in use, and not enough details on how to use them within the context.
Next up was Hexo, which if you noticed the callout in the footer, was the winning choice. Good documentation, simple build system, and easy configuration were all wins for me. I needed to focus on content, not code, and Hexo fit the bill.
Hosting / Deployment
So I've been enamored with AWS lately, and wanted to try out an idea I had. Hosting websites is pretty easy on S3, so I decided to do that. The only problem is that using cross-region replication with a static site would involve a lot of setup, configuration, and could be costly.
So I cheated.
I decided to just use CloudFront as my global distribution platform from a single bucket, and point my DNS records at that resource instead. This is cheaper, because there are less transfers on my bucket, and simpler because I don't have to set up any sort of intelligent DNS forwarding, just point it at Cloudfront and let them deal with it. 😉
I switched my domain to Route53 a while ago so I could play around with AWS, so that decision was easy.
So implementation took some time. My first attempt was sans-cms using create-react-app, which was great, but playing with it was getting in the way of creating content. After that was my brief tussle with Gatsby, mentioned above. Finally I got going with Hexo, which was pretty easy to configure.
The theming system uses .ejs files for templates and partials, and I had a pretty easy time creating some to my liking. I basically just copied the default theme, "landscape", and tweaked it to my liking. They were mostly just CSS changes, but I found that I could reference the configuration variables such as 'description' and made use of those for the header and footer.
... <section id="main"> <p id="main-description"><%= config.description %></p> <%- body %> </section> ...
I added a bunch of posts, took a photo of my desk for the header, then geeked out on making myself into an 8-bit icon for the favicon:
... good times.
Platform / Deployment
Okay, so it's time to go live with this biaitch.
I created an S3 bucket with public read access, and the "Serve Static Website" option checked. They warn you about this now, apparently a buncha fools were saving highly private data in publicly accessible buckets. Boo to them and whatever political party they happen to represent.
That being done, I had Hexo generate the static files, then synced them up like so:
$ aws s3 sync . s3://natecornell.com/ --acl public-read
And that was that.
Started setting up CloudFront to serve the bucket to everyone in the world(!!) and realized that I didn't have an SSL cert. "Who cares?" you may say, "me". It's my blog, I do what I want!
Bounced over to the AWS Certificate Manager and had a valid cert in minutes. It was awesome.
After getting CloudFront set up with the cert and pointing it at the bucket, things were looking good.
Added a couple aliases in Route53 for www.natecornell.com and natecornell.com to point to the CloudFront resource.
This is where things got a little funky.
After loading the site up, what I got was a bunch of raw XML (forgive me for not getting a screenshot) with an "Access denied" type message.
I did a couple things to resolve it:
- Set the "Default Root Object" to 'index.html':
- Set the "Origin Domain Name" the buckets public website URL, rather than just using the resource name. This reduces your flexibility, but forces it to use http requests only.
After that, everything looked great!
...Oh, wait, except my site section names are in french:
Turns out I had set the language incorrectly:
author: Nate Cornell language: English timezone: America/Los_Angeles
But that was easily fixed by setting it the correct identifier:
author: Nate Cornell language: en timezone: America/Los_Angeles
I now have my own, super-awesome blog, and it's got globally distributed servers for nearly nothing! So cool!
I think in the future I'm going to think long and hard about any sort of dynamic web application with backend rendering to see if there's a better way. Maybe S3, Cloudfront, and a couple Lambda functions could get me farther than I think right now...