Lots of blog-related changes with the new year. My hosting subscription with Bluehost was due for renewal. But I couldn’t stomach the non-promotional annual price + all the nickle-and-dime addons. So I looked into alternatives and discovered a much cheaper hosting set up. Saved 95% of my yearly costs.
Migrating was kind of a pain, but I learned a lot about cloud and the infrastructure of the internet in the process (bit of an exaggeration…it was mostly just DNS stuff).
hosting setup
I kind of predetermined my new hosting setup based on tech I was somewhat familiar with. I knew I’d use Azure to do whatever hosting I needed to do and hugo
for the site generation. Hugo is a static site generator that I heard of a while back and always kept on my radar. It uses markdown files to generate a static site and the framework seemed full-featured enough for anything I will ever need. Static sites can also be served dirt-cheap 💰 since they don’t require you to run any servers.
Since my new blog would just be a static site, I could host it from a cloud storage account if I wanted. But Azure actually had a new-ish service called Azure Static Web Apps that is designed to do the same thing with a bit more first-class support for things like github, custom-domains, and SSL. The free tier of this service provides more than enough capacity for anything my blog could ever need. Bonus points, they even had a “Getting Started”-type tutorial for integrating this service with a hugo site.
Once I went through that getting started tutorial, my next steps were
- migrating content off wordpress
- choosing and configuring a theme
- migrating the domain.
Throughout this whole process, my methodology was to get proof-of-concepts working quickly. I’ve learned after working on lots of projects that if you try to polish before you publish, you lose momentum. The best trick to maintain momentum is to frequently see the results of your effort.
migrating off wordpress
I saved all the content from my existing Wordpress site in a couple of different formats. Wordpress lets you download an export of your existing site in convenient xml, which I did. But then I also just ctrl+s
saved every blog post as html files. I could have written a web-scraper to do this (I’ve written a few before), but I only had like 20 blog posts, so I just went the old ctrl+s
route. One advantage of this as opposed to strictly scraping for content, I can look at the old html files if I ever want nostalgia for what my old blog looked liked 😥. I took those html files and wrote up a quick python script using BeautifulSoup
to parse the html and extract out the actual contents of the blog posts. That content got saved into text files (to eventually be converted to markdown).
choosing and configuring a theme
Hugo has a pretty large library of blog themes. I chose PaperMod after playing around with a few different themes. It is minimalist, supports a bunch of stuff I don’t need but might someday, and provides sensible extension points for customization. I found out I needed those customization points because markdown doesn’t support LaTeX
which is a must for my blog. You just can’t write math without LaTeX
. There’s a cool library called MathJax
that was easy enough to add as custom javascript to the site.
I also wanted to implement a search for my site. Azure has a search-as-a-service offering, which I tried out. But ultimately decided just to go with fusejs
, which does search client-side. It makes sense, I only have like 20 blog posts, so a hosted search is just throwing money away. Bonus points, it’s super easy to integrate fusejs with my chosen theme.
migrating domain
This is the fun DNS part. Azure allows you to set up custom domains using DNS CNAME records. Short summary of CNAME records as told by someone who kinda understands DNS.
5th grader: Hello sir. I am a Boomer time-traveling 5th grader and I would like to know how DNS works.
Kinda DNS guy: This is a completely plausible scenario. I will describe DNS to you. Let’s say you want to go to your friend’s house, but you have no idea where they live. They never told you their address. You could knock on every door in the town and see if it’s your friend’s house, but that might take too long. Instead, you can find your friend much more quickly if you go to a phone book that has everyone’s name and address. When you find your friends name in the phone book, you also find their address. DNS is like the phone book to the internet.
5th grader: Thank you. That was so well explained. Could you also explain CNAME records?
Kinda DNS guy: A CNAME record is like an entry in the address book that tells you to go somewhere else. Imagine a household where each person has an entry in the address book. For this example let’s consider a mom, her son, and their dog - Jane Doe, Jimmy Doe, and their dog Rufus. Jane and Jimmy both have their address listed as 123 Maple Street. Rufus used to have his address listed at 123 Maple Street, but he wants his mail forwarded to a different address where the Doe’s can’t read it. Rufus has a friend named Fido who is trustworthy, so Rufus creates a CNAME record that tells the phone company to list his address at wherever Fido lives. The next time the phone company updates the phone book they update Rufus’s address to “wherever Fido lives”. You can then look up Fido’s address to find where you should send mail intended for Rufus.
5th grader: Can everybody in the family forward their mail in this way?
Kinda DNS guy: Well…no. You see, the DNS system was designed in the 1980s, and they didn’t envision all the ways the internet would work back then. So for the sake of this example, everybody can change their address except Jane. She has to stay listed at 123 Maple Street because she is the parent in the family. Parents can’t forward their addresses.
5th grader: [Becoming increasingly intelligent for plot-advancement purposes] That doesn’t seem fair. Jane should be able to update her address. Doesn’t this restriction make it hard for cloud-hosting services to provide SAAS product offerings using commoditized hardware over a vast global infrastructure?
Kinda DNS guy: Yes it does make it hard. But some special DNS providers created ways to fake address changes for Jane. If you list your CNAME record in their phone book, Jane can change her address.
5th grader: Oh, so like what Cloudflare does with CNAME Flattening.
Kinda DNS guy: [impressed and kinda scared at 5th graders ability to assimilate information] 👀 Yeah… That’s one way.
Un-fifth-gradering that colorful dialogue and summarizing the hard-earned lesson with DNS. Making www.bradypramberg.com
point to my new blog, easy as pie. Just create a new CNAME record with my DNS provider. Making bradypramberg.com
point to my new blog, technically impossible (according to the DNS spec). I eventually just had to migrate my DNS provider to Cloudflare, because they support CNAMEs on root urls (using a clever implementation on top of the DNS spec).
I also learned quite a bit about TTL (time to live) and the dig
, whois
, and nslookup
commands. TTL is how long it takes DNS changes to propagate. The dig
, whois
, and nslookup
commands are ways to query DNS information (some of which is authoritative(!) and some of which is cached and old).
A fun(?) and hair-pulling exercise. Make significant DNS changes (like changing your domain provider and DNS provider at the same time) and then run dig
commands to see inconsistent results for a few days.
$$ savings
All told I went from a yearly bill of $173 to $9. Savings of 95%. The previous stack was Bluehost + Wordpress with most of the cost being in the monthly hosting. The new stack is Cloudflare + Hugo + Azure + Github with the only cost being the domain name.
Wrap up
I’ll miss my Wordpress site. And if you’re thinking of starting a blog, Wordpress + Bluehost is a pretty good starting place. The promo prices are usually pretty decent.
I used tutorials and google-fu to set everything up with my current site. So the Cloudflare + Hugo + Azure + Github stack is pretty approachable for someone with a bit of technical savvy. But as always, use whatever’s easiest to get your POC up and running and then iterate from there. Crank that feedback loop.