Moving crtv.dev from Ghost to Astro

The old crtv.dev was taken down and its posts were lost. Here's how I rebuilt every post from the Wayback Machine, why the blog now runs as a static Astro site on Cloudflare, and what I learned about backups.

If you’ve been here before, you might notice things look a little different. crtv.dev is no longer a Ghost site. It’s now a static site built with Astro and served from Cloudflare.

This wasn’t a planned redesign. Earlier this year, the old Ghost install was compromised and every post on it was deleted. The server is gone now, and rather than rebuild the same setup, I took the chance to rethink how this blog runs. This post covers how I got the content back, why I went static, and a few lessons about backups that I learned the hard way.

The old setup

Since launching in July 2023, crtv.dev ran on Ghost, self-hosted on a DigitalOcean droplet. Ghost is a great publishing platform: a lovely editor, built-in newsletters, member management, and themes that look good out of the box.

Self-hosting it also meant I owned everything underneath it: the Linux server, Node, the database, the Ghost application, the admin panel, and every update in between. I even wrote a post about keeping Ghost updated on a droplet. For a long time, that worked fine. Until it didn’t.

Getting the content back

When the content was deleted, I went looking for backups and found none old enough to help (more on that below). What I did have was the next best thing: the Wayback Machine. (Yes, I wrote about it back in 2023. It turned out to be more useful than I ever expected.)

I wrote a couple of small scripts to do the recovery:

  1. Find every URL. The Internet Archive had captured the site’s sitemaps over the years, so I pulled every post and page URL from the most recent ones.
  2. Grab the newest good snapshot. For each URL, the script picked the latest archived capture of the page from before the content was deleted.
  3. Convert Ghost HTML back to Markdown. Each page’s article body became a Markdown file, with the title, date, tags, excerpt, and feature image moved into front matter.

A few things made this more interesting than a simple scrape:

  • Three posts were never captured as pages. Their full text only survived inside archived copies of the site’s RSS feed, so they were rebuilt from that.
  • Ghost’s cards don’t map cleanly to Markdown. Bookmarks, callouts, toggles, and the raw HTML cards that power the interactive demos all needed special handling. Some HTML cards even had blank lines that, once converted, made Markdown treat half of a demo’s markup as a code block.
  • Not every image was archived. The posts referenced 32 images hosted on the old server. The Wayback Machine had 17 of them, which now live alongside the site. The other 15 are gone for good, so a few posts are missing screenshots.

In the end, all 42 posts and 5 pages came back. If you’ve ever wondered whether the Internet Archive is worth supporting, this is your sign to donate.

Why static beats a self-hosted CMS (for me)

With the content back as a folder of Markdown files, the question was where to put it. I could have stood up a fresh Ghost server and imported everything. Instead, I went static.

There’s much less to attack. A self-hosted CMS means a server, a database, an admin login, an API, and an application runtime, each of which needs patching and each of which is a way in. Now every page is a plain HTML file generated at build time. There’s no admin panel, no database, and no server process of my own sitting on the internet. The site’s attack surface went from “a whole Linux box” to “my GitHub and Cloudflare accounts.”

The content lives in Git. Every post is a Markdown file in a repository. That means version history for every edit, a full copy on every machine that clones it, and another on GitHub. If the site disappeared tomorrow, getting it back would be a single deploy, not a weekend of scraping the Wayback Machine.

No more babysitting a server. Keeping the OS, Node, Ghost, and MySQL patched is real, recurring work, and it’s easy to fall behind on a side project. A static site on Cloudflare doesn’t have anything for me to patch. Updating the site’s dependencies happens on my machine at build time, not on a server that’s live on the internet.

It’s fast and cheap. Static files served from Cloudflare’s edge are about as fast as the web gets, and hosting a blog this way costs next to nothing compared to keeping a droplet running.

The fun parts still work. I was worried about losing the interactive demos, like the boolean logic playground and the S-curve chart. Astro is happy to render raw HTML inside Markdown, so they made the move intact.

What I gave up

Static isn’t free of trade-offs. Ghost gave me a nice writing editor, built-in email newsletters, and member management. Those are gone. I write in Markdown in my editor now, and the best way to follow along is the RSS feed.

I still like Ghost. If you’re running a publication with a team of writers who aren’t comfortable writing Markdown and would rather work in a visual editor, it’s a great choice, especially as a hosted service. For me, though, the benefits were outweighed by the cons. I’m comfortable in Markdown, I don’t need memberships, and running a whole server for what is, at the end of the day, a folder of articles just wasn’t worth it. I’ll happily trade those features for a site that’s simpler, faster, and much harder to take down.

Lessons about backups

The most useful thing I can share from all this is about backups, because mine didn’t save me.

  • Retention has to outlast detection. My backups ran on a rolling schedule, and older ones were deleted automatically. By the time I noticed the content was gone, every backup from before that point had already rolled off. A backup only helps if you still have one from before the problem started. Keep some long-lived snapshots (monthly, yearly) and not just a rolling window.
  • A backup on the same box isn’t a backup. If something can delete your data, assume it can delete the backups sitting next to it too. Keep at least one copy somewhere separate.
  • Export your content in a portable format. A database dump only helps if you can stand the same software back up. Plain Markdown and image files can go anywhere.
  • Monitor what matters, not just uptime. A site can return a perfectly healthy “200 OK” while serving none of your content. Check for the things you’d actually miss.
  • The Internet Archive is a safety net, not a plan. It saved most of this blog, but not all of it, and it can’t help with anything that was never public.

What’s next

The archive is back, the old URLs redirect to their new homes, and the site is easier to maintain than it’s ever been. Now I can get back to the actual point of this blog: writing.

Thanks for sticking around.

#devops#cloudflare#ghost#wayback-machine