I needed a little diversion from writing this week (you can only hammer on something for so many hours in a day for so many days in a row), and so I decided to do some much-needed work on my website. My intention was to discontinue use of my custom static site generator and replace it with something off the shelf—most likely, my old nemesis Wordpress.
Then I setup a Wordpress dev instance and almost immediately remembered why I stopped using it in the first place.
After looking around at few other options, I quickly came to the conclusion that pretty much all "off the shelf" solutions suffer from a common problem. If you are creating a site from scratch, Wordpress and others will give you a fairly simple onboarding process. Pick a theme you like, customize some colors and fonts, maybe add some widgets (if supported by the theme), and then away you go. Just add your content (images, pages, and posts).
However, if you already have a website—and you like the way it currently looks and works—recreating that site in those off the shelf content management systems is a royal pain in the ass. Because basically, every CMS uses their own theming system, and if you want your new CMS-based site to look and work like your existing site, well... you're in for a metric crapton of work.
- Step 1: spend a week or more poring over (sometimes sparse, misleading, or outdated) documentation to learn how to make a theme for your choice of CMS that closely approximates your existing site.
- Step 2: spend a week to a month writing and debugging said theme.
As Kimberly "Sweet Brown" Wilkins once famously opined, "...ain't nobody got time for that."
There were a few reasons I started using a static site generator in the first place:
- Tighter security with no database backend and no server-side code execution.
- Better performance because I'm only serving static files.
- Easier administration meant no need for admin panels, etc.
- More streamlined content creation because everything is just a text file, and all I need to create or edit, is an editor.
But along with those upsides, came a few issues:
- File sprawl. Because everything is a static page, for paginated content
like blog posts, you end up with
index2.html, etc. Which can become problematic when a visitor bookmarks your website, not realizing they bookmarked
index37.htmlinstead of the root document. And what's worse is that as you add more posts, the contents of
index37.htmlwill change. A month later the content that was on
index37.htmlis now on
index39.htmland the user's bookmark is invalidated.
edit/build/deployworkflow may (depending on your tooling) require some very specific environment dependencies which can become brittle over time. System updates, library updates, moving to a new computer, etc., can all break your build environment. And if you don't have the best documentation or some composable implementation, it can be tricky to recreate the same setup you cobbled together a year prior.
- SSGs can become a bit of a time-sink. You write up a post, kick off your build, and then get an error. Maybe it's a quick fix, maybe it's several hours to get the thing working again. Meanwhile, you just wanted to make a blog post...
Anyway, so I wanted to get off the SSG but the road to Wordpress or another CMS would just be too long. I can divert off my book project for a few days, not a few weeks. What I came up with was basically a hybrid solution.
- A PHP-driven backend "CMS-lite" based around the assembly of webpages from component parts via includes. This was fairly easy to put together just by taking my current SSG templates and CSS, and replacing Jinja code with PHP code (sort of).
- A flat-file data model consisting of JSON files. While not as human-readable as YAML, JSON is still plain text. And actually, after dealing with some of the peculiarities and ambiguities that arise from YAML's human-friendliness, I've actually come to prefer JSON's more regimented structure and predictable behavior. Even if you can't wrap long strings (which kind of sucks).
- A self-contained LA
MP stack wrapped up in a Podman container. Which makes deploying my site (along with all of its dependencies) to a new host a simple matter of
rsyncing a directory and adding a
systemdunit file. For the frontend, I still proxy behind NGINX like all my other (static) sites.
Adding content to my new site is a matter of writing the content into a file, and then adding an entry to the JSON "database." Deploying the change involves copying/updating both files to a directory on my host and running a server-side script to update the Atom feed. With about 30 seconds of work, I wrote a bash script to automate a new post deployment. So, write post, update database file, run script. Done.
Making edits is just "edit file, run script again." Which I've done about five times so far (I should have proofread better, sorry).
All of the site content, and everything related to my website (even the
Apache config files)
is stored and version-controlled in a local
git repo and backed up
offsite with the rest of my stuff.
With this system, I get a flexible, dynamic site where I can add more advanced features, but I also keep a flat-file, read-only (to the app layer) data model with better performance and (somewhat) better security than with something like Wordpress. And I was able to convert my old static site with minimal style/structure changes in a matter of about three days. That's not a huge time investment. And I think I spent more time tweaking CSS for a visual update than I did writing backend code...
The only real downside of this new solution is that it's still bespoke code that I'll have to maintain (which is something I was trying to get away from). But since the version of the containerized backend is pinned, the "host" of my site is more or less frozen in carbonite, and I shouldn't incur any issues with unplanned changes occurring from some random system update.
Unless an update brings a breaking change with Podman itself, but I've only had that occur once—with an in-place upgrade from Debian 11 to Debian 12. And because that upgrade was planned (and I expected some kind of issue to occur) I had already set aside the time to address any failures that followed. (Plus, simply recreating the affected pods resolved the problem, anyway. Quick fix.)
Anywhooo... we'll see how it goes with this new site model. Now back to finishing my book (sometime this year, please).