We're now blogging on Ghost!
We already had our own blog, so why migrate? Why choose Ghost? What does it all meeeaaan?
Why migrate?
The Bscotch Blog has already been through a couple of migrations, since we've been in operation for over a decade. First it was on Blogspot, then we migrated it to a custom Wordpress instance, and then I brought it into my bespoke web infrastructure ("Rumpus") that I built to solve all kinds of problems for our studio and players.
Why did I build my own blog platform? Well, at the time I was looking around for something I could integrate with Rumpus for authentication, and it quickly became clear that it would be easier to write my own than to try to hook Rumpus into something that already existed. And it was pretty easy: I already had user accounts and a general storage system in Rumpus, so I just had to deal with front-end and design issues.
The Rumpus blogging platform was simple, and janky, since we didn't need anything fancy, and only had a few people on the team who would ever use it. And it served us pretty well for 6 years, which I think is pretty good!
Enshittification and Age Laws
Eventually, though, the Rumpus blog decayed to the point where it was creating problems. Being attached to the Rumpus monolith made it very difficult to maintain, and things just started to slowly become even more janky than in the original design.
But what really spelled the end was something else: age verification laws, of all things.
The Rumpus blog didn't have its own image hosting. It's something I just never bothered to deal with since, hey, we could just use Imgur for free and then not have to deal with the bandwidth or building management system. Over the years, though, Imgur has gotten increasingly terrible as an image hosting platform. The writing has been on the wall, so to say, for a while now.
And then a bunch of idiots who don't know how technology works or what privacy means started legislating that websites and apps "verify" people's ages. Imgur got caught up in that, and suddenly our UK readers couldn't see our images anymore!
(I assume that's why that happened, anyway. It's also possible that Imgur hit peak enshittification itself. Ultimately it doesn't really matter why.)
So now we had a janky blog system that wasn't pleasant to use and no easy answer for where the heck to host images for any posts we wrote. That meant I needed to either find a solution to the image hosting problem, or move to a blogging platform to solve two problems at once.
After a bunch of research into options, I ultimately decided it that migrating the blog was the move.
But migrate to where?
There are tons of blogging platforms and more-general CMSes out there. How to choose? I wanted something that satisfied the following:
- Node.js based (I enjoy using a single(ish) programming language across the stack)
- Images can be linked without CORS restrictions, making cross-posting easy
- Has decent support for Markdown
- Does a reasonable job of converting pasted HTML sources into blog content (because Steam uses BBCode for everything, which nothing is compatible with, but we can always copy Steam's rendered HTML to cross-post to other places that support that)
- Has a decent API (we like to automate things)
- Has both self-hosted and managed options. (I want to make everything someone else's problem, but also be able to leave if the host jacks up prices, provides bad service, or starts to enshittify things.)
- Positive community vibe and a stable leadership (or at least not a visibly unstable leadership)
I already knew about Ghost and it seemed to fit all those criteria, so I went right for it and didn't try to find other options.
How'd it go?
Well, you're here! So it seems to have worked out. Though I only JUST completed the migration, so hopefully I don't end up feeling like it was a mistake!
The process was pretty rough. And mostly for reasons that I think were Ghost's fault, though I'll always admit to potentially doing things stupidly. Here's a summary of how I made the migration and the trouble I ran into:
- I used my own Rumpus APIs to download all of the posts from the Rumpus blog. They're in Markdown with associated metadata, so this was easy-peasy. There were about 470 posts.
- I then wrote a script to identify all image links, download them (to get them off of Imgur, mostly), and change the links in the posts so that they'd map onto the images in their new locations on Ghost. This took some doing, in particular because I couldn't figure out where images end up when uploaded to Ghost: could they be in different directories? Eventually I figured out that they all live in a huge pile at
/content/images/. - I then wrote a script to zip and upload those images to Ghost in batches up to 20MB. Rather than read docs to figure out how to do this, I just uploaded some images via the admin UI (with the "Universal Import" button), opened up the browser's Dev Tools to see what request was made, copied it as a fetch request, and then plopped it into a script with a few modifications.
- Finally, it was time to get all of the posts on there! I looked at the Ghost migration docs to see what the data format was, and through a lot of trial and error got my content converted into that format. I ran into a LOT of issues at this point, though. The main one being that YouTube embeds in my posts would nearly always cause the upload process to fail. But sometimes the very same post would work! Eventually I found that if I split my posts into Lexical blocks to separate the embeds from the rest of the Markdown, it would work. There were still about 20 posts that failed for mysterious reasons, and at that point I'd spent a day fighting the cryptic 406 errors with embeds and just decided to create those ones manually.
- Once everything was migrated I did a bunch of cleanup. In the process I learned that it's VERY easy to accidentally delete a tag, and that when trying to fix that with the API it's very easy to create duplicates of tags. The API and Universal JSON documentation are both quite sparse, in particular with respect with what kind of identifiers should be used. I generally expected that I'd be sending
idvalues, which would make the most sense, but things typically treated anything I sent as a "name" (and then duplicated things instead of overwriting). Which is all to say, it was WAYYY too easy to make a huge mess.
Fortunately I'm comfortable hacking and scripting, and so I was able to fight my way through the process. Pretty frustrating, though. I can't say I recommend doing this migration if you, too, are coming from a bespoke blogging platform. They do have importers for other major platforms, though, which I imagine makes for a much smoother migration.
Anyway, after getting everything migrated to Ghost I still had to update the original site to excise all of the blogging stuff out of it, add redirects to make sure all the links out in the wild end up at the new location, etc etc. It's a lot of things to keep track of, so surely I've missed something...
So... what does this mean?
This will make it much easier for our team to write and post news about our games, articles about making games, and even help documents and the like. So, in theory, we'll be posting more stuff than we have been over the past few years. But even if there isn't much change in the content we're putting out, it'll at least be a lot easier for us to do it!