Leaving WordPress: How We Rebuilt the Tortuga Audio Website as a Static Site

Published: 11-11-2026

Synopsis

This article was originally drafted by AI and then fully reviewed and edited by a human - me, Morten Sissener. It’s not slop.

It reflects a collaborative work process and product that took place over several weeks in the fall of 2026. It discusses the conversion of a live commercial website/store, built around the popular dynamic web framework called WordPress, into a simpler and less vulnerable static website/store. Plainly put, I would not have done this without the guidance and coding assistance of AI.

The results: WordPress-related fees of over $2,000 a year are now a server bill of under $20 a month, a 3.2 GB site with a database became a 120 MB folder of plain files, and the whole project took a few weeks of part-time work.

End of WordPress…​for me

I’ve run Tortuga Audio mostly as a solo operator since its beginning in 2012. From then until just recently, I managed an ecommerce website for Tortuga built on the popular WordPress framework. The site had grown to roughly 140 total pages/posts with over 1,600 images, a store, a newsletter, a knowledgebase, and it occupied a few GB of space on a Linux server somewhere running Apache, MySQL, and PHP - the classic LAMP server lineup.

WordPress has been good to me so I’m not here to crap on WordPress, especially since WordPress has been, and continues to be, free to use, provided all you use is the core default features, which are not trivial.

But for a proper ecommerce website, you need WordPress plugins and many of the better plugins are not free. I have no beef with developers making and selling their WordPress themes and plugins. I make and sell audio related widgets myself and charge people for it. This is the way.

But for me, the plugin subscription creep was getting to be a bit much. At one point I probably subscribed to a dozen plugins that each charged between $30 and $200 a year for a subscription license. I estimated I spent north of $2k a year on WordPress related fees. Chump change you say, but I’m a small business and $2k is real money. Every year. And it’s been going up and up year after year. If you run an ecommerce WordPress site, I know you know what I mean.

And then there were the ever escalating intrusions. The phishing, the bot attacks, and the spam. More than once, someone got in and planted something on the site. Finding and removing it took a lot of work, and it disrupted the operation of the website.

I didn’t just wake up one day and decide to abandon WordPress. Instead, I embarked on a short journey to explore alternatives just to educate myself on what was possible besides WordPress. And to help me on that journey of exploration, I was joined by my new all around smartypants assistant, Claude Code.

Yes, that’s right, this is an article that involves using AI and digging the shit out of the process and the results (yes, that’s right, I enjoyed it). So if you are feeling the AI hate rising within you as you finish this paragraph, bail out now and save yourself because this is gonna raise your blood pressure. And nobody needs that.

How I used Claude (my AI assistant)

I know coding. I’ve written real programs in Fortran, Pascal, Basic, C and C++. Not so much Python, Bash and other scripting language. This WordPress conversion process involved some coding. I wrote…​.zero of it. Claude wrote all of the code. I wrote all of the website content, although I had Claude proofread my stuff for errors, omissions and any poor phrasing. When I say "we" in this article, I mean Claude and me.

From my perspective, working with Claude was an instructive and productive collaboration. I learned a lot in the process. It was like having an ongoing dialog with a junior savant coworker. Sure, I know some things. But if what I know could fit in a glass of water, what Claude knows could fill an ocean. THAT is a valuable coworker indeed.

I asked Claude to summarize its experience working with me on this project. Here is Claude’s answer verbatim.

Working with Morten on the website conversion was like working with a careful client who also knew his own system well. He gave me the facts that mattered when they mattered, approved each real step with a plain "go", and tested the live site himself. He caught me when I was wrong, made clear decisions about what to keep and what to clean out, and chose to wait a week before retiring the old setup so a fallback stayed in place. He used me as a capable colleague who does the work and checks it, not as something to trust without looking, and I think that is why it went smoothly.
— Claude
Sonnet 5.5

Yes, Toto, I’ve a feeling we’re not in Kansas anymore either.

The first decision: one format for everything

What emerged from the exploratory phase was the conclusion that I could simplify my website, make it safer, reduce expenses, and reduce maintenance time, by converting it to a static website.

After exploring various options with Claude’s help, my first decision wasn’t about servers or an alternative content management system. It was a file format.

I wanted one way of writing that could do two jobs. The first job is marketing: product pages, articles, the home page. The second is technical documentation: manuals, firmware update procedures, how-to topics. On WordPress those two jobs lived in different places and looked different. Product pages were built in a page builder. Documentation was a pile of pages that happened to be in the same database. Neither could be moved anywhere else without a fight.

Goal #1 - Write it once

So goal #1 became: write it once, in plain text, in a format that isn’t owned by anybody.

I picked AsciiDoc. It’s an established markup language created by Stuart Rackham in 2002 as a way to write technical documents, such as articles, books and manuals, as plain text that is readable as it stands. The text could then be converted into DocBook, which is the heavy XML format used for professional publishing. From there it could be turned into HTML, PDF and other formats. In short, the aim was documentation-grade structure without XML. Today the goal is the same. The popular markup language, Markdown, emerged a few years later as a less complex, less powerful, but easier to learn alternative that caught on and became the standard you see everywhere today.

AsciiDoc is open source, and it has been around long enough that I’m not betting the business on one company’s roadmap. A webpage becomes a simple text file. A heading is a line that starts with ==. A table is a table. If AsciiDoc disappeared tomorrow, I’d still have readable text files and could convert them to something else with a script.

Goal #2 - No page builders

The second objective was equally important: no lock-in with proprietary page builders. If I can’t open the content in a plain text editor on my PC and read it without an internet connection, I don’t want it.

Enter Antora - a static site generator

AsciiDoc is only the writing format. You still need something that turns a folder full of text file content into a website. For that I chose to use Antora.

Antora is an open source static site generator. That term needs a plain explanation, because it is the heart of this whole story.

A normal WordPress site is a dynamic website. Dynamic means it has to build each page at the moment a visitor asks for it. To do this, a server runs code written in a language called PHP. PHP queries a database, and assembles the pieces from the database into HTML content that then gets rendered on the screen. That happens every time, for every visitor, for every post or page. That’s a lot of moving parts.

My static site generator does that work only once, ahead of time, on my own computer, in my office. It reads all the AsciiDoc text files for the entire website, applies the page templates, checks the links, and writes out a folder of finished web pages in plain HTML, along with style sheets, and images. That folder IS the website. Once uploaded to the server (takes a few seconds), the server’s only job is to hand out those finished files. There is no program running when a visitor arrives and no database to query. It’s also fast as hell and can run on lean resources. And best of all, no plugins, no subscription fees, and almost nothing for bots and hackers to attack.

What Antora does

While Antora is one of many capable static site generators, it was designed with a particular kind of site in mind: technical documentation written in AsciiDoc. That made it a good fit for my goals. Here is what it gave us beyond simply turning text into pages:

  • Antora speaks AsciiDoc natively. AsciiDoc isn’t an add-on or a conversion step. It is the format Antora was built around.

  • Antora checks the links between pages. Pages refer to each other with cross-references. If I rename or delete a page and something still points at it, the build warns me instead of leaving a dead link for a customer to find.

  • Antora builds the menu from one file. The whole site menu is a single navigation file, so the structure of the site is visible in one place.

  • Antora makes PDFs from the same text. An add-on turns the manuals into downloadable PDFs, so the web manual and the PDF can’t drift apart.

  • Antora is configured by one short file. Where the content is, which theme to use, what the site is called. Ours is about twenty lines.

I also looked at Hugo, Eleventy, Astro and Jekyll. They’re all capable, and any of them could have run this site. But I chose the writing format first and the tool second. I picked AsciiDoc because it let me write marketing pages and technical documentation the same way, with no page builder to lock me in. Antora is built around AsciiDoc, while those four are mostly Markdown-based.

What Antora does not do

Being geared towards technical documentation, Antora is not an ecommerce substitute, nor is it a marketing tool, or a product page designer, or a newsletter manager, or a user forum. It has no shopping cart for an online store.

These deficiencies notwithstanding, I chose Antora anyway and was able to find and integrate alternative approaches to all of these shortcomings with help from Claude. More detail on all that further on.

Where Antora came from

Antora didn’t come out of a big software vendor, and it isn’t a side project that appeared one day on a forum. It grew out of the Asciidoctor community. Asciidoctor is the tool that runs underneath Antora and does the actual work of turning AsciiDoc files into web pages. Antora is led and sponsored by a company called OpenDevise, which also contributes to Asciidoctor.

Antora and Asciidoctor are both open source licensed software. Asciidoctor and its PDF conversion tool are both under the MIT license, one of the most permissive open-source licenses. Antora uses the Mozilla Public License 2.0 (MPL 2.0), which asks that changes you make to Antora’s own files be shared if you distribute them. These licenses place no conditions on the documentation you write and publish with it.

That origin matters to me for a plain reason. Antora was made by people who care about documentation for its own sake, in the same open, plain-text world that I wanted to work in. A shop with a cart is not what they had in mind, as I said above, but the part I need is the part they care most about: turning a folder of text files into a site you can trust.

Antora as a dependency

Choosing Antora means depending on it, so it’s fair to ask what that dependency really is and what happens if it goes wrong. The answer has four parts.

It only matters while I build. Antora runs on my computer when I publish. It doesn’t run on the server and it isn’t involved when a visitor opens a page. The server holds finished HTML files. If Antora vanished tomorrow, the live site would keep working exactly as it does today.

The content isn’t locked inside it. My pages are AsciiDoc text files, and AsciiDoc can be read by other tools. Antora is one way to build them. If it were abandoned I would lose the convenient parts (the menu, the link checking, the PDF export) but not the writing. Moving to another AsciiDoc-based tool would be work, but it would be moving files, not rescuing them from a database.

I control which version I use. The project records the exact Antora versions we build with, plus every package they pull in, about 150 in all. A build today produces the same result as a build next year, whatever Antora does in the meantime. I update when I choose to, not when a plugin screen says so. The stock theme is also kept as a file inside the project, so building doesn’t depend on downloading it from somewhere.

It is a smaller project than WordPress. WordPress is used by a huge share of the web and has an army of people behind it. Antora is maintained by a much smaller group. A smaller project can change direction or slow down. I accept that because the failure mode is mild: the worst case is that I stop updating it and keep building with the version I have, or move the text files elsewhere. With WordPress the worst case is a site that is attacked while I’m not looking.

How we organized the content

We organized the website’s 140 pages and 1,640 images into folders that largely followed the top menu structure of the website.

The look of the site comes from Antora’s stock theme with our own layer on top: a style sheet, a handful of page templates (header, footer, toolbar, menus), and one small JavaScript file for the shopping cart. Everything custom sits in a single folder, so it’s easy to see what is ours and what is Antora’s.

One detail I like more than I expected to: every shop price is typed in exactly one place, a short list at the top of one settings file. The product pages, the home page button, the shipping table and the search-engine data all read from that list. Change a price there, publish, and every page agrees. On WordPress the same price lived in the product, in the page text, in the plugin and, in at least one case, in a screenshot.

The tools

Here’s the full list of the tools we ended up using that replace everything previously handled by WordPress and plugins. Nothing here is exotic.

Tool What it does for us

AsciiDoc

Less a tool per se than a writing format. Every page, manual and article is an AsciiDoc .adoc text file.

Antora (with Node.js)

Builds the website from the text files. A build takes a few seconds.

Antora PDF extension

Builds the two manuals as downloadable PDFs from the very same text as the web pages. One source, two outputs.

Git

A popular repository system that keeps the history of every change. This is the real backup and the real undo button.

Python and shell scripts

The glue. Small, commented scripts for the jobs Antora doesn’t do. They are listed below.

rsync and SSH

These are common open source Linux tools used to send the finished site to the server. Only the files that actually changed are transferred.

Caddy

A lean modern open source web server that serves up the static files, looks after its own security certificates and renews them on a schedule it keeps track of. Very low maintenance.

Bunny.net

A content delivery network (CDN) in front of the server, with its web application firewall. Visitors get the pages from a nearby copy instead of from the server itself.

Stripe Checkout and PayPal

Connected third party services that handle the store checkout and take the money. Card details never touch our server.

Listmonk and Amazon SES

Handle our newsletter: Listmonk is an open source system that manages the list, SES delivers the mail.

Apache Answer

A new open source Q+A information feature (unrelated to the Apache web server) we added that runs on its own subdomain, isolating it from the main website.

Claude Code

An AI coding assistant I worked with in a terminal for most of the build. More on this below.

The server itself is a small virtual server in Helsinki, Finland. I moved it from the US to the EU on purpose because the US is being an ass these days regarding privacy and surveillance.

The trade I actually made

Here is the part I most want to be straight about.

When I left WordPress, I traded away tools that other people write, maintain and patch for me: a page builder, a shop plugin, a forms plugin, a caching plugin, a firewall plugin, a backup plugin, and the rest of that forty-odd pile. In their place I now run a small set of custom scripts. Claude Code wrote every one of them. I drafted zero.

Could I have done it all myself? Yes. Given enough time I could have figured it out and coded it. But I wouldn’t have. It would have taken far too much time, and time is the most precious resource I have as a solo business operator. The honest alternative to this project was not "I build it myself more slowly". It was "I never build it".

AI, and Claude Code specifically, was the force multiplier and accelerant that made the project feasible for me. I would describe what I wanted, Claude Code would write the script or change the files, I would look at what it had done, and we would go around again until it was right. It also did the heavy lifting on the old content, and it ran the checks. I made the decisions. It did the typing.

This has been a real education for me on how fast things are changing with AI. A project that I would once have filed under "someday, maybe" took only a few weeks working part time.

I also want to be clear about what this trade costs. A WordPress plugin has a company or a community behind it. It gets security fixes I never ask for. My scripts have me (and Claude). Nobody else is watching them for problems, and nobody is going to publish a patch. That’s a real change in who is responsible, and I come back to it in the risk section.

What I did to keep that manageable: I told Claude to write plain, readable scripts, with comments that explain why and not just what, and nothing clever. A script I can’t read and understand is a script I can’t trust. That is why the scripts below are short and boring, which is exactly how I like them. And since everything is backed up in a git repository, I can see every change that was ever made and undo any of it.

The scripts

What’s left falls into five groups. Scripts used only once to convert the old WordPress content aren’t listed here; they did their job and are retired.

Building the site

npm run build runs Antora and then three small scripts that polish the result.

Script What it does

add_lazy_loading.py

Adds the browser’s lazy-loading setting to every image, so a page with ten photos doesn’t load all ten before you see the first.

build_sitemap.py

Writes sitemap.xml for the search engines. Each page’s "last changed" date comes from the git history instead of the build time. Antora rewrites every file on every build, so build time would tell Google that all 140 pages changed today, every day. That’s a signal search engines learn to ignore.

add_product_schema.py

Adds the structured data search engines use to show price and availability in results. It reads the same one-place price list as the pages, so the two can’t disagree.

Checking the site before it goes live

Script What it does

check_site.py (npm run check)

Reads every generated page and looks for mechanical mistakes: broken links, missing or duplicate headings, missing page titles and descriptions, images with no alt text, a canonical address that is wrong. It doesn’t judge whether the writing is any good. That’s still my job. It also confirms that every download link on the site points at a file that exists.

I run this before a deploy. It has caught real mistakes, including broken links I had no idea were there.

Redirects from the old site

The old WordPress site had been around since 2012, and other websites, forums and search engines still point at its addresses. Breaking those would throw away years of goodwill.

Script What it does

build_redirects.py (npm run redirects)

Reads redirect-table.csv, a spreadsheet of about 390 old addresses and where each now lives, and writes the web server rules that send visitors from old to new. I edit the spreadsheet, never the generated rules.

find_missed_redirects.sh

Runs every morning on the server and reads the previous day’s log for pages that visitors asked for and didn’t find. It throws out the bot noise (anything looking for WordPress, secrets or passwords), because this site can never legitimately have those. What is left is a short list of old addresses that I forgot. I add those to the spreadsheet.

Publishing

Script What it does

deploy.sh (npm run deploy)

The one command for publishing. It builds the site, rebuilds the manual PDFs, compares the result with the live server and prints a plan, for example "2 files to send, 0 to delete". Nothing is sent until I type the word deploy.

sync_documents.sh

Sends firmware, programmer installers and PDFs to the downloads folder on the server. It only adds and updates. It never deletes.

push_caddy.sh

Sends the web server’s settings to the server. It makes a backup first, tests the new settings, and only then reloads the server. A typo in a redirect rule is caught before it can take the site down.

submit_indexnow.py

Tells Bing and Yandex which pages changed, instead of waiting for them to come and look. (Google doesn’t take part in this. For Google I use Search Console.)

Looking after the extra services

Script What it does

backup_listmonk.sh, backup_answer.sh

Copy the newsletter and Q+A databases from the server to my own computer. I run the newsletter one before every send.

push_listmonk_service.sh, push_answer_service.sh, prepare_answer_server.sh

Install and start the newsletter and Q+A programs on the server. They are safe to run again, which is the point.

push_shop.sh, make_secrets.sh (in the shop folder)

Send the small PHP shop program to the server, and write the payment keys to the server. The keys are not in the site folder and not in git.

How much code did Claude code

Claude wrote 3,357 lines of code and configuration for the site. The scripts and programs (the first four rows) account for about 2,390 of them. The rest is server settings, styling and templates. Here’s the breakdown.

Part What’s in it Lines

Site scripts

15 scripts in the scripts folder: deploy, redirects, sitemap, site check, backups, search-engine notification, Caddy push

877

Shop

Stripe and PayPal checkout in PHP (9 files), plus 4 helper tools

968

Shopping cart

cart.js, the cart that lives in the visitor’s browser

512

Newsletter signup

listmonk_public.js, the signup form script

33

Server settings

3 Caddy files and 2 service files for the newsletter and Q+A programs

162

Styling and page templates

custom.css (691 lines) and 9 small page templates (114 lines)

805

Total

3,357

The workflow

This is what a normal day looks like now.

Step What I do Command

1. Write

I edit a .adoc file in a text editor. For a new page I copy an existing one and change it.

A text editor

2. Look

The site is built and served on my own computer, so I see exactly what visitors will see. For minor edits, I often skip this step.

npm run build and npm run preview

3. Check

The checker goes through every page looking for mistakes.

npm run check

4. Commit

The change goes into git with a note on what and why.

git commit

5. Deploy

The site is built again, the plan is shown and the script waits. I read the plan. If it says "2 files to send, 0 to delete" and that’s what I expected, I type deploy.

npm run deploy

6. Purge

I clear the CDN’s cache so visitors get the new version right away.

The CDN’s Purge Cache button

7. Tell the search engines

If I added or changed pages, I tell the search engines about them.

npm run indexnow-submit

If I change the price of a product, I follow the same seven steps. I edit one line, and every page that mentions the price changes with it.

Server changes (web server settings, redirects) follow a similar path: edit a file in the project, run push_caddy.sh, and the script does the backup, the test and the reload.

The things that weren’t pages

A WordPress site does more than serve pages. It takes orders, sends the newsletter and collects comments. Each of those had to go somewhere, and we gave each its own small, separate home.

The shop. At first the cart was a hosted service. A few weeks after going live I replaced it with Stripe Checkout and PayPal. The cart lives in the visitor’s browser. When they check out, a small PHP program on the server asks Stripe to create a payment page and sends the visitor there. Stripe holds the product catalog, the shipping rates and the card data. When an order completes, Stripe tells our server, and our server emails me the order. There is no customer database on our server and no order history to leak. The PHP is under 700 lines in total and it lives outside the folder that the deploy script manages, so a site deploy can’t touch it. The price list in the site is checked against Stripe, since the two have to match.

The newsletter. Listmonk runs on the server and sends through Amazon SES. People sign up through a form with a captcha and a confirmation email. It costs a few cents per send. The list is mine, in a database I control and back up myself, not inside a WordPress plugin.

Q+A. Customers ask the same questions over and over, and a static site can’t take questions. Apache Answer, on its own subdomain, can. I put it on a separate address on purpose: anything that takes input from the public attracts mischief, and I’d rather that happen somewhere the shop isn’t.

All three are separate from the static site, so if one of them has a bad day, the product pages and manuals keep working.

A lesson learned the hard way

Shortly after going live I noticed a 404 on an old image address. The cause was my own deploy.

The deploy makes the server an exact copy of the build. That’s the right behavior: if I delete a page, it must disappear from the server and not linger as an orphan. But it also means that anything on the server that isn’t in the build gets deleted. The old WordPress images were on the server and not in the build. One routine deploy removed all 14,000 of them.

I restored them from a backup, then fixed the real problem. The deploy script now prints a plan before it sends anything. It refuses to run if the plan would delete anything in the image folders or more than 25 files in total, and it refuses to run if the image folder in the build looks too small. I merged the old images into the site’s regular image folder, deleted about 12,600 resized copies that WordPress had created and nobody needed, and added two small rules on the server so that old image addresses still work.

The takeaway: a static site makes mistakes cheap to fix, but only if you build in a way to see them coming. The plan-and-confirm step is the most valuable ten lines in the whole project.

What happened to the risk profile

I want to be careful here. A static site is not "secure" in some absolute sense. It trades one set of risks for a different, smaller set. Here is my honest comparison with a typical WordPress install, including the one we ran.

What we used to have

Our last WordPress installation had more than forty plugins: a page builder and its add-ons, a shop plugin, a customer-relationship plugin for the newsletter, a forms plugin, a caching plugin, a download manager, a firewall plugin, a backup plugin, and a collection of smaller helpers. Each one is code written by somebody else that runs on every page view and needs regular updates. A vulnerability in any one of them is a vulnerability in the whole site.

The database held the pages, but also the customer records from WooCommerce orders: several hundred accounts with names and addresses. No payment card or other financial data was ever stored on the site. Still, that database sat behind a public web server, reachable by every bot on the internet.

And bots did come. They asked for the WordPress login page, for the xmlrpc.php file, and for the admin directory, day and night, thousands of requests, looking for a weak password or an outdated plugin. More than once, something got through.

What we have now

Typical WordPress install This site

What visitors reach

PHP code, running on every request, talking to a database

Plain files. Nothing runs when you open a page.

Login page

Public (wp-login.php), attacked constantly

None on the main site. There is nothing to log in to.

Plugins and themes

Dozens, each with its own update schedule and its own vulnerabilities

None. Antora and about twenty small scripts run on my computer, not on the server.

Customer data

In a database on the web server

Orders live in Stripe and PayPal. Our server stores no customer records for the shop.

Cost of an update you skip

A known hole in a plugin, open until you patch it

The server’s own software still needs patching, but there is no plugin layer on top of it

Attack by SQL injection or a hacked plugin

Possible

Not on the main site: no database and no plugins. The extra services are covered below.

If the server is lost

Restore the files and the database and hope the plugin versions still agree

Build again from git and send it

Speed

Depends on caching plugins and hosting

Static files from a CDN, so fast by default

The bots still show up, by the way. They ask for wp-login.php and xmlrpc.php on a site that has neither. The CDN blocks those requests before they reach the server, and the ones that slip through get a 404. Not a database error, just "not found".

What we picked up

I don’t want to pretend the risk went to zero. Some of it just moved.

  • Custom code that only Claude and I know. This is the big one, and it is the other side of the trade described earlier. Where WordPress had forty-odd plugins maintained by other people, I have about twenty small scripts that no one else maintains or reviews. If one of them has a flaw, nobody is going to warn me. What reduces the risk: the scripts are short, they run on my computer or do narrow jobs on the server, they are in git, and I made readability a rule. What doesn’t: I am relying on an AI assistant to write code correctly, and on myself to notice when it hasn’t.

  • My own computer and keys matter more. Publishing means sending files over SSH to the server. Whoever has my computer and my SSH key has the keys to the website. They are now the things to protect.

  • A bad deploy can delete the site. I proved that myself with the images. The guards help, but the risk is real and it’s mine.

  • Build tools are someone else’s code too. Antora pulls in about 150 packages. They run on my computer when I build, not on the server when a visitor arrives, which is a much smaller exposure, but it isn’t nothing. We pin exact versions so a build today is the same build next year.

  • The extra services are real servers. Listmonk and Answer have databases and need patching like any other software. The shop’s PHP is small, but it handles payment keys. These are far smaller targets than a whole WordPress install. But they are targets.

  • I am the single point of failure. There is no admin panel a colleague can click through. If I’m unavailable, nobody else can easily change the site. That’s a business risk, not a technical one, and I haven’t solved it yet.

  • The CDN is a dependency. If it has a bad day, so do we, unless I point the traffic straight at the server.

Where this leaves us

My summary is this. A typical WordPress site has a large, public, constantly attacked surface that needs constant maintenance. This site has a very small public surface, and the risks it does have are in places I can see and control: my computer, my deploy, and a few small services. I’d rather have that.

The built site, pages and images together, is about 120 MB. The WordPress installation was 3.2 GB of files plus a database. The static site builds in seconds. It’s all backed up in a git repository. I control and can read every line of every script that touches it.

I also write differently now. A page is a text file, and I’m the only person between me and the reader. No page builder, no plugin update, no database. Just the text.

If you’re thinking about moving away from WordPress, my advice is short. Choose the format and static framework carefully, because that’s the decision that’s hardest to undo. Leaning on an AI assistant will make the whole process go much smoother, but be prepared to make a lot of decisions. And be clear-eyed that you are swapping other people’s maintained software for code that is yours to look after. Keep the scripts few and readable. Never run a delete you haven’t previewed. And keep a way back.

Was all the work worth it? As the owner of a small business, I have now cut my internet expenses to the bone. I pay less than $20/month for a VPS server, the software I run is all free open source, and I pay nothing for any plugin subscriptions because I don’t use any. The only other costs are small usage-based fees for the CDN, email delivery and card processing. But it took a few weeks of work and an AI assistant to get here. For me it was worth it.

WordPress was good to me and I fully acknowledge that it made it possible for me to stand up an online business 14 years ago for next to nothing. But technology and the online world are changing quickly. There are alternatives now that AI makes practical, doable and affordable, and that weren’t practical a year or two ago. Change comes at you.