Patching your PHP/WordPress on AWS? Don’t Do It Twice

Last week a critical PHP vulnerability dropped. That same week, I realized the WordPress image my blog runs on was never going to get another update. Those two facts together changed what “patching” meant for me, and they probably change it for you too if you host WordPress on AWS Lightsail.

Here’s what happened, what I did, and why I think rebuilding is cleaner than patching.

The vulnerability

On October 21, PHP shipped emergency releases for two flaws researchers named PHP2Shell (CVE-2026-109618 and CVE-2026-109619). Both allow unauthenticated remote code execution. Attacks were already showing up before the fix was public. The fixed versions are 8.5.12, 8.4.27, 8.3.36, and 8.2.35, and the only real fix is upgrading PHP and restarting every worker. The mitigations PHP published are explicitly partial.

So far, so normal: a bad PHP bug, and you update PHP. Except on my server, I couldn’t.

The Bitnami problem

Like a lot of people, I launched my site years ago from Lightsail’s one-click WordPress image, which Bitnami packaged. It’s a great way to get started. But Bitnami bundles its own copies of PHP, Apache, and OpenSSL under /opt/bitnami. They don’t come from the operating system’s package manager, so apt upgrade doesn’t touch them.

And AWS has stopped updating those images. Bitnami-packaged Lightsail blueprints have received no updates since May 19, 2026. Starting November 19, 2026, you can’t launch new instances from the Bitnami WordPress blueprint at all. Your existing server keeps running, and you can still launch from your own snapshots, but nobody is going to ship you a patched PHP.

That leaves two options when a PHP emergency hits:

  1. Patch Bitnami by hand: build PHP yourself and swap it in.
  2. Move to an image that gets security updates, and let the next emergency be someone else’s packaging job.

I did both, in that order, and the second is the one I’d recommend.

Option 1: patching by hand (it works, and that’s the trap)

With exploitation already happening, I wanted the hole closed that day. So I:

  • Took a Lightsail snapshot first. Always.
  • Turned off PHP’s session upload progress (session.upload_progress.enabled = Off), one of PHP’s published partial mitigations.
  • Downloaded the PHP 8.4.27 source, verified its checksum, and built it in a Debian 12 container on my laptop using the exact configure flags Bitnami had used. You can see them in php -i.
  • Copied the build to the server next to the old one, carried over the config and extensions, swapped directories, and restarted.

It worked. Every page came back byte-for-byte identical, and PHP reported 8.4.27. Then I spent an afternoon checking whether anyone had gotten in during the window. (No sign of it.)

But think about what I’d actually done: I’d become the maintainer of a custom PHP build. The next PHP security release, the next OpenSSL fix, the next Apache CVE all land on my desk again, with the same container, the same configure flags, and the same swap. And that image is never getting easier to maintain.

If you’re going to put in an afternoon anyway, put it into getting off the image.

Option 2: build a new server, then move the address

Lightsail now offers its own WordPress blueprint (wordpress_ls_1_0), which isn’t packaged by Bitnami. Under the hood it’s plain Debian 12 with Apache, MariaDB, and PHP from Debian’s packages, and unattended-upgrades is switched on. When Debian ships a PHP security fix, the server installs it. For PHP2Shell, Debian’s fix for PHP 8.2 was already out.

The plan was simple:

  1. Build the new server next to the old one. Nothing about the live site changes.
  2. Move the whole site across. That means the database dump, all of wp-content (themes, plugins, uploads, mu-plugins), and the few PHP and Apache settings the site depended on.
  3. Test the new server privately, by its own IP, before anyone sees it.
  4. Move the static IP from the old server to the new one.

That last step is the elegant part. My domain’s DNS points at a Lightsail static IP, not at a server. Lightsail lets you re-attach a static IP to a different instance in one call. So the “cutover” wasn’t a DNS change with propagation delays and stale caches. It took a few seconds, and nothing measurable went down. Rollback is the same move in reverse, and the old server sat there untouched the whole time.

I didn’t use AWS’s own migration guide. It walks you through WordPress’s XML export and import, which brings over posts but leaves behind your theme, plugins, settings, users, and plugin data such as newsletter subscribers. Move the database and the files instead.

The details that would have bitten me

The broad plan is easy. These are the things that weren’t:

  • The new image shipped with a vulnerable PHP. Its package lists were as old as the image. Run apt-get update && apt-get full-upgrade and reboot before anything else, then check dpkg -l php8.2-common.
  • It runs PHP as mod_php, which PHP’s advisory calls the highest-risk setup for this bug. I switched to PHP-FPM, as the old server had.
  • It’s missing extensions that Bitnami bundled: intl, imagick, bcmath, soap, sqlite3, and more. Compare php -m on both servers.
  • It doesn’t read .htaccess. WordPress’s permalink rewrites, and any deny rules you rely on (I block xmlrpc.php), have to go into the Apache site config.
  • phpMyAdmin is linked into the web root and publicly reachable by default. Lock it down.
  • wp-config.php lives one level above the web root, and the default config builds the site URL from whatever hostname the request used. Pin it to your real URL.
  • Files outside wp-content don’t come with it. My favicon.ico sat in the web root and quietly went missing until I compared responses.
  • PHP version went down, not up. The old server ran 8.4 and the new one runs Debian’s 8.2. I syntax-checked all ~950 PHP files in my plugins and theme under 8.2 before trusting it.
  • Get the HTTPS certificate after the move. I copied the existing certificate over so there was no gap, then issued a fresh Let’s Encrypt certificate with certbot once the domain pointed at the new server.

Then the most important step: compare, don’t eyeball. I requested every important URL from both servers by IP (the homepage, posts, the REST API, the feed, search, media, the 404 page, login) and compared status codes and byte counts. They matched exactly before I moved the IP. They matched again after.

Why this is the better patch

If you’re on Bitnami and PHP2Shell has you patching anyway, here’s the comparison:

Patch Bitnami Move to the Lightsail image
Fixes PHP2Shell Yes Yes
Fixes the next PHP, Apache, or OpenSSL bug No, you rebuild again Yes, through Debian security updates
Effort An afternoon, every time About an afternoon, once
Downtime A restart Seconds, during a static-IP move
Rollback Swap directories back Move the IP back, with the old server intact
Future after November 19 A frozen image A normal Debian server

I went one size up (1 GB instead of 512 MB) while I was at it. The old server was squeezing Apache, PHP, and MySQL into about 450 MB and dipping into swap. It’s $2 a month more, and the site now has room to breathe.

A word about the help

I didn’t do this alone. I did it with an AI coding agent, and it did most of the legwork: the build, the inventory, the byte-for-byte comparisons, the gotcha list above. My job was the one I keep writing about: deciding, approving each irreversible step, and owning the result.

That turned out to matter. Partway through, the agent found that a previous session had left an important piece of infrastructure config stranded in a git stash. It also had to tell me it had been using credentials more broadly than my own written rules allowed. Both were caught because the work happened in the open, with plans reviewed before anything changed. Delegation is great. Accountability still doesn’t delegate.

What I’d tell you to do

If you run WordPress from Lightsail’s Bitnami image:

  1. Today: check your PHP version (php -v). If it’s below the fixed versions, set session.upload_progress.enabled = Off and restart PHP-FPM as a stopgap.
  2. Before November 19: take a snapshot, build a Lightsail-packaged WordPress instance next to your current one, move the database and wp-content, test it by IP, and move your static IP.
  3. If your domain doesn’t point at a static IP yet, fix that first. It turns the scariest step into the easiest one.

You can patch PHP on Bitnami. I did. But if you’re going to spend the afternoon anyway, spend it once.

Subscribe to the newsletter

Leave a Reply

Your email address will not be published. Required fields are marked *

Recent

From the blog

All writing