Why I Left WordPress (and Dodged a PHP Zero-Day)
I’ve always enjoyed tinkering with my web stack to stay on top of how modern technologies and developer workflows evolve. Seven years ago, I wrote about migrating this site from shared hosting to an AWS Lightsail VPS with Let’s Encrypt. That Bitnami WordPress setup was a faithful workhorse for the better part of a decade.
Recently, though, I wanted a change.
It wasn’t just about aesthetics. In my day-to-day work, I found myself increasingly inspired by the interactive artifacts (calculators, reactive charts, parameter sliders) that modern AI coding tools can generate. But trying to embed bespoke interactive code inside a WordPress block editor was like trying to fit a jet engine into a chariot. While it was technically possible using messy <iframe>’s, WordPress was simply never built for that kind of customization. Worse, it locked every post and revision away inside MySQL database tables, making it difficult to edit posts or glean text from multiple at once (without just opening many browser tabs).
So I decided to pull the plug on WordPress and rebuild the entire site from scratch using Astro 5 hosted on Cloudflare Pages (with a fair amount of help from AI coding agents along the way).
Here is why I made the switch, the architectural choices underneath it, and how I inadvertently managed to avoid a (frightening) PHP Zero Day by doing so!
The Push: Governance Drama and the Attack/Upgrade Surface
Three distinct factors pushed me to leave WordPress behind.
First was the ongoing annoyances of running a PHP content management system (CMS). A self-hosted WordPress deployment means maintaining an unmanaged Linux server with an active PHP runtime and a database exposed directly to the public internet. Such a stack demands some babysitting: applying security patches (as PHP and its vast plugin ecosystem are relentless targets of hackers), debugging Let’s Encrypt renewal errors when certificates expire, and auditing third-party plugins.
Second, Bitnami (following its acquisition by Broadcom) quietly walked away from providing upstream updates for its AWS Lightsail WordPress blueprints. While AWS eventually rolled out its own WordPress blueprints, moving off the deprecated Bitnami image would have required a painful, manual server migration anyway. If I was going to spend a weekend doing that, it made sense to rethink the underlying foundation.
The final push came from governance and ecosystem drama at Automattic, the company behind WordPress. A sequence of controversies surrounding WordPress and its CEO Matt Mullenweg — most notably Automattic’s escalating legal war with WP Engine, the unprecedented forced repository takeover and renaming of Advanced Custom Fields (ACF), and the introduction of mandatory loyalty checkboxes on the WordPress.org login page — made the platform feel like it had lost its way. When core technology infrastructure becomes a political weapon to be wielded in a commercial dispute, it ceases to be a reliable ecosystem, but a risky dependency. I didn’t want my personal writing platform dependent on the whims of a centralized ecosystem. I wanted out.
Architectural Choices: Why Astro + Cloudflare Pages?
Rather than just swapping one CMS for another, I used the migration to re-architect the site from first principles.
Moving to Astro and Cloudflare Pages fundamentally shifted every layer: the infrastructure (always-on VPS vs. serverless edge), the runtime (PHP vs. static pre-rendering), media storage (VPS-attached disk vs. Cloudflare R2), and web distribution (a single AWS Lightsail instance in one region vs. Cloudflare’s global edge network).
- Origin:
- Single Ubuntu Linux VPS (Fixed AWS Region)
- Runtime:
- Apache + PHP 8.x + MySQL Monolith
- Storage:
- Local disk with redundant auto-thumbnails
- Content:
- MySQL tables via WYSIWYG block editor
- Edge CDN:
- 300+ Cities Globally (Sub-50ms TTFB)
- Runtime:
- Zero Server Runtime (Pre-rendered HTML)
- Storage:
- Cloudflare R2 (WebP originals, $0 egress)
- Content:
- Git Content Collections (MDX + Astro Embeds)
| Stack Layer | Legacy: Monolithic VPS (AWS Lightsail, 2019–2026) | Modern: Serverless Edge (Astro 5 + Cloudflare Pages) |
|---|---|---|
| Origin / CDN | Single Ubuntu Linux VPS (Fixed AWS Region) | 300+ Cities Globally (Sub-50ms TTFB) |
| Runtime | Apache + PHP 8.x + MySQL Monolith | Zero Server Runtime (Pre-rendered HTML) |
| Storage | Local disk with redundant auto-thumbnails | Cloudflare R2 (WebP originals, $0 egress) |
| Content | MySQL tables via WYSIWYG block editor | Git Content Collections (MDX + Astro Embeds) |
1. Serverless Edge, Custom Integrations, and Zero Maintenance
Instead of spinning up another virtual machine on AWS Lightsail or DigitalOcean to host Node or Docker containers, I opted for a serverless deployment on Cloudflare Pages.
The practical benefits were immediate:
- Zero server maintenance and global distribution: There are no operating systems to patch, no background daemons to crash, and no SSH keys to manage. Every page is pre-compiled at build time and cached across Cloudflare’s worldwide network rather than served from a single, un-replicated VPS.
- Generous free-tier and media hygiene: Cloudflare’s generous free tiers across its Pages, Workers, D1, and R2 products easily handle a personal blog, eliminating a monthly compute bill for what is mostly an idle server. During the cutover, I took advantage of the transition and pruned thousands of redundant, automatically generated WordPress thumbnails, compressed all master images to the modern WebP format, and offloaded them to Cloudflare R2 for more performant image serving.
- Lightweight custom integrations: Leaving a monolithic CMS meant replacing some WordPress / plugin functionality with modular alternatives. For the email newsletter, I ditched Jetpack and wired my build pipeline directly to Buttondown (which is why subscriber emails now come through Buttondown rather than WordPress). For reader comments, I built a lightweight serverless endpoint using Cloudflare Pages Functions backed by an edge SQLite database (Cloudflare D1), secured by Cloudflare Turnstile to block bot-spam.
2. Static Generation, Speed, and Composable Interactivity
Switching the frontend to Astro and MDX improved both performance and creative flexibility at once.
By default, Astro compiles every article into flat, static HTML with minimal client-side JavaScript. Essays and posts load almost instantaneously. But whenever an essay calls for interactivity, MDX lets me import and embed bespoke UI components directly. I get total control over component layout, styling, and reactive state — things a standard CMS editor could never handle gracefully, but which modern AI coding tools are great at (or at least far better than I am).
A clear example of this is my deep dive on Why is it so Hard to Build a Diagnostic Business?. In the original WordPress version, explaining why high-accuracy screening tests suffer from surprisingly low Positive Predictive Values (PPV) required static screenshots, awkward <iframe> embeds, and external spreadsheet links. With Astro, I can embed interactive sensitivity, specificity, and disease prevalence sliders directly in the page so readers to see the math play out in real time on embedded clinical and economic calculators.
3. Git-Backed, AI-Ready Corpus
With Astro Content Collections, my entire writing archive — every essay, reading note, and portfolio project — now lives in a single Git repository as plain Markdown and MDX files.
This has two advantages:
- Version control: Every typo fix, structural edit, and component tweak is tracked in atomic Git commits with clean diffs and instant rollback capability.
- AI tooling synergy: Because the entire archive lives locally in text files rather than inside opaque MySQL tables, AI coding tools can search, analyze, cross-reference, and refactor the entire blog at once. Auditing links, reformatting, and building new interactive widgets went from tedious chores inside a clunky WordPress admin page to AI-assisted workflows.
4. Why I Passed on Cloudflare’s Emdash
During the planning phase, I also evaluated Emdash, Cloudflare’s open-source CMS built natively for Astro on top of Workers, D1, and R2. Emdash is an ambitious effort to build a modern “spiritual successor to WordPress”, complete with sandboxed plugins (historically the primary vector for WordPress security vulnerabilities).
Ultimately, I decided against it for two reasons. First, Emdash is still in its infancy, and adopting an early-stage CMS contradicted my primary goal of long-term simplicity. Second, adopting Emdash also meant buying back into the CMS mindset with an admin dashboard, a database, and a server runtime.
But, I didn’t want a “better” CMS. I wanted a directory of text files and code.
Why Astro Matters Here (A Slightly Gratuitous Demo): The interactive scroll-driven breakdown below is a somewhat gratuitous demonstration of the kind of bespoke experience that would have been a nightmare to build and maintain inside a traditional CMS like WordPress. It was also pretty simple to put together with AI coding tools.
Interactive Architecture Breakdown: On the web, this section features an interactive scroll-driven diagram comparing the old and new stacks across four pillars (view the live interactive experience on benjamintseng.com →).
Here is the summary of the four pillars:
1. Serverless & Edge CDN — Why Host, Use Cloudflare’s Global Network: The worst parts of VPS administration revolved around security, networking, and updates. Going serverless eliminates that entirely, while also upgrading web distribution from a single un-replicated AWS Lightsail box to Cloudflare’s global edge network across 300+ cities with built-in caching and DDoS protection. (Distribution: 300+ Edge Locations)
2. Static Security — Serving Static HTML, Not PHP: PHP and its plugin ecosystem are constantly hammered by hackers and automated vulnerability scanners, requiring regular security updates (as the recent PHP2Shell zero-day showed). With Astro on Cloudflare Pages, there is no PHP, no server-side code to render posts — just pre-built static HTML. (PHP Attack Surface: 0 — HTML only)
3. Cost-Efficiency — Generous Cloudflare Free Tiers: With a traditional VPS, you pay a fixed monthly compute bill 24/7 even when nobody is reading your site. Cloudflare’s free tiers across Pages, Workers, D1, and R2 easily cover a personal blog’s traffic at $0/month, and pruning WordPress’s auto-generated image thumbnails into compressed WebP keeps storage lean. (Media: 419 WebP Assets on R2)
4. Composability & AI — Interactive Components & AI-Ready Repo: Storing the entire blog as plaintext
.mdxfiles in a single Git repository means version-control and easy access for AI tools. Astro’s component model also makes it trivial to create custom layouts and bespoke visualizations inside an essay. (Stack: Composable MDX + Git + AI)
Why Change the Architecture
Scroll through the four pillars below — or click the tabs — to see how the stack changes across infrastructure, security, cost, and authoring experience.
Why Host, Use Cloudflare’s Global Network
The worst parts of VPS administration revolved around security, networking, and updates. Going serverless eliminates that entirely, while also upgrading web distribution from a single un-replicated AWS Lightsail box to Cloudflare’s global edge network across 300+ cities with built-in caching and DDoS protection.
Serving Static HTML, Not PHP
PHP and its plugin ecosystem are constantly hammered by hackers and automated vulnerability scanners, requiring regular security updates (as the recent PHP2Shell zero-day showed). With Astro on Cloudflare Pages, there is no PHP, no server-side code to render posts — just pre-built static HTML.
Generous Cloudflare Free Tiers
With a traditional VPS, you pay a fixed monthly compute bill 24/7 even when nobody is reading your site. Cloudflare’s free tiers across Pages, Workers, D1, and R2 easily cover a personal blog’s traffic at $0/month, and pruning WordPress’s auto-generated image thumbnails into compressed WebP keeps storage lean.
Interactive Components & AI-Ready Repo
Storing the entire blog as plaintext .mdx files in a single Git repository means version-control and easy access for AI tools. Astro’s component model also makes it trivial to create custom layouts and bespoke visualizations inside an essay (like this scroll-experience).
A Lucky Coincidence: Dodging PHP2Shell
There was one final footnote to the migration that was incredibly lucky. Just days after I finished migrating to Cloudflare Pages, security researchers publicly disclosed PHP2Shell (CVE-2026-109618 / CVE-2026-109619).
The vulnerability is a critical pair of unauthenticated Remote Code Execution (RCE) flaws in the core PHP parser. Because it exploits memory corruption before application-level code or authentication logic even executes, an attacker can compromise a vulnerable server simply by sending a request to an affected server over the internet!
Had I still been running that Bitnami WordPress instance on Lightsail, I would have had to SSH in, migrate to the new AWS Lightsail WordPress stack, upgrade its PHP packages, and verify nothing broke. Instead, because Astro pre-compiles every post into static HTML at build time, there is literally no PHP runtime or server to worry about. I inadvertently dodged one of the most severe PHP zero-days in history simply by migrating a little earlier.
What’s Next
Web publishing doesn’t need to be confined to passive columns of text. While I’m not going to turn every essay into a software application, having the flexibility to embed interactive models, reactive charts, and bespoke presentations when the topic calls for it makes writing on the web fun and exciting again.
If you spot any broken links or layout quirks from the cutover, feel free to leave a note below — the comment section now runs on serverless Cloudflare Pages Functions and an edge SQLite database (Cloudflare D1).
Here’s to cleaner code and (hopefully) more interesting content ahead.
Stay updated via email
Get new essays on healthcare, biotechnology, operational models, and curated reading directly in your inbox.
Discussion
Moderated for qualityLeave a Comment
Your email address is never published. Comments are approved manually before appearing.