Deploy WordPress on Red Hat Hardened Images and image mode for Red Hat Enterprise Linux to spend less time fighting vulnerabilities, and more time shipping features.
If you've ever inherited a poorly executed WordPress deployment, then you already know the pain of a general-purpose server with a package list that sprawls across things you never asked for and wouldn't miss. A CVE scanner pings you every other week about something installed in 2019 that nobody remembers touching. A production environment that has drifted so far from what anybody intended that "just redeploy it" is not a real option anymore.
This post is about fixing that, from the ground up, using Red Hat Hardened Images and image mode for Red Hat Enterprise Linux. With these, you can build a WordPress deployment that's reproducible, minimal, and genuinely maintainable by the people who built it (which is to say: you).
What WordPress actually is (and why developers should care)
Here is some quick context, because this matters for the architecture decisions ahead.
WordPress launched in 2003. Matt Mullenweg and Mike Little forked a dead blogging engine called b2/cafelog and published something you could actually run. It started as a personal publishing tool and grew—faster than anyone expected—into the most widely used content management system on the planet. Today it powers over 40% percent of all public websites.
That number is not a coincidence. WordPress made a bet on the LAMP stack—Linux, Apache, MariaDB, PHP—at a time when those four technologies were already well-understood and widely deployed. The bet paid off. The combination is stable, well-documented, and supported by an enormous ecosystem of plug-ins, themes, and hosting providers.
WordPress itself is GPL-licensed. That means you can run it on your own infrastructure, modify it however you need, build custom plugins, fork it, extend it—none of which requires a license fee or vendor approval. It is open source in the genuine sense.
What developers actually use WordPress for
- Publishing platforms: News sites, technical blogs, documentation portals. The block-based Gutenberg editor makes structured content manageable for non-technical contributors without requiring developers to maintain a custom CMS.
- E-commerce: WooCommerce turns WordPress into a full shopping experience. Thousands of online stores run on it.
- Portals and intranets: Internal knowledge bases, onboarding hubs, gated content—WordPress handles access control and content organization well enough that many teams reach for it before building something custom.
- Custom web applications: The plug-in ecosystem and REST API make WordPress a reasonable foundation for applications that need content management as a feature, not as the whole product.
The common thread: WordPress is infrastructure that a non-developer can operate once you set it up. That is valuable. It means you build the platform once and hand it off, rather than becoming the permanent owner of every content update.
The real problem With a traditional LAMP stack
Here is what installing a LAMP stack actually produces: A full general-purpose Linux distribution with Apache, MariaDB, and PHP layered on top. That distribution ships with hundreds of packages your workload never uses.
Every unused package is a potential vulnerability. Every potential vulnerability shows up in your security scanner. Every scanner alert is something your team has to triage, assess, and either patch or document as a known exception. Most of those packages have nothing to do with running WordPress.
The noise is real, and it costs real time.
Red Hat Hardened Images take a different approach. They start from a minimal footprint—only the software required to run the specific workload is included. Fewer packages. Fewer CVEs. Less noise. The scanners still run, but the signal-to-noise ratio is dramatically better.
For a developer, the practical effect is this: You get paged less often about things that do not matter, which means you have more time to work on things that do.
Why image mode for RHEL changes the deployment problem
There is a second issue with traditional LAMP deployments: They drift.
You stand up a server, configure it, test it, and deploy it. Day one, everything matches what you intended. Then six months pass. A package gets updated automatically. Someone tweaks an Apache config to fix a prod incident and does not document it. A plug-in requires a new PHP extension that gets installed manually. The running system gradually diverges from anything reproducible.
The result: You cannot reliably redeploy. You cannot confidently promote from staging to production. You cannot guarantee that what worked in your local environment also works in the next environment.
Image mode for RHEL treats your core operating environment as an immutable artifact. You build it once. You test that artifact. You deploy that artifact. The running system is exactly what you built, and the core system software cannot drift, only the application layer.
Updates follow the same model. Build a new image, test it, roll it out. Roll back if something breaks. The whole thing works like software releases—because it is a software release.
For a developer, this means your local operating environment and your production operating environment can be genuinely identical. Not "pretty similar" or "configured the same way" but the same artifact, running everywhere.
Building the stack: From LAMP to WordPress in image mode for RHEL
Red Hat has published a new learning path, Build a hardened LAMP stack and deploy it in image mode for Red Hat Enterprise Linux, that walks through building the hardened LAMP stack foundation. The learning path gets you a running LAMP stack on Red Hat Hardened Images. This article provides the complete picture, including the WordPress installation layer you add on top.
You must complete this learning path before you can follow the steps in this blog post, so go do that now! Already completed the learning path? Jump straight to step 2 and install WordPress.
Step 1: Run the LAMP Stack in Hardened Containers
The learning path starts off by building Apache, MariaDB, and PHP containers using Red Hat Hardened Images as the base—distroless, micro-sized images that include only the packages required for each service to function.
Each component gets its own container. Apache handles HTTP. MariaDB owns the database. PHP processes your application code. They communicate over a container network. You run the whole thing locally to verify it works before adding any deployment machinery.
This step establishes the foundation. Everything after this builds on it.
Step 2: Install WordPress into the application directory
The learning path provides you with a working LAMP stack. The key thing to understand about this project's architecture: WordPress files do not go inside a container image. The web root (/srv/www on the bootc host) is mounted into both the Apache and PHP-FPM containers at runtime as /var/www/html. You add WordPress by populating that directory, which Containerfile.bootc handles with COPY app/ /srv/www/.
Download WordPress and put it in the app/ directory of the project, replacing the sample index.php:
curl -O https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
cp -r wordpress/. app/
rm -rf latest.tar.gz wordpressNext, create app/wp-config.php. The environment variables—DB_HOST, DB_USER, DB_PASS, and DB_NAME—are injected into the PHP-FPM container by the Quadlet unit file, with the database password coming from the mariadb_app_password Podman secret. Connect wp-config.php to read those exact variable names:
<?php
define( 'DB_NAME', getenv('DB_NAME') ?: 'hellodb' );
define( 'DB_USER', getenv('DB_USER') ?: 'appuser' );
define( 'DB_PASSWORD', getenv('DB_PASS') ?: '' );
define( 'DB_HOST', getenv('DB_HOST') ?: 'mariadb' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
// Generate real keys at https://api.wordpress.org/secret-key/1.1/salt/
define( 'AUTH_KEY', 'replace-with-unique-value' );
define( 'SECURE_AUTH_KEY', 'replace-with-unique-value' );
define( 'LOGGED_IN_KEY', 'replace-with-unique-value' );
define( 'NONCE_KEY', 'replace-with-unique-value' );
define( 'AUTH_SALT', 'replace-with-unique-value' );
define( 'SECURE_AUTH_SALT', 'replace-with-unique-value' );
define( 'LOGGED_IN_SALT', 'replace-with-unique-value' );
define( 'NONCE_SALT', 'replace-with-unique-value' );
$table_prefix = 'wp_';
define( 'WP_DEBUG', false );
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
require_once ABSPATH . 'wp-settings.php';The database hostname is mariadb—the container name defined in mariadb.container, which the shared Podman network resolves using DNS. The password never touches the image, but is injected at runtime through the Podman secret.
One important detail: The PHP-FPM container in this project runs as UID 65532, not as apache. WordPress needs write access to wp-content/uploads for media uploads. Add a chown to Containerfile.bootc after the existing COPY app/ line so the right user owns that directory:
COPY app/ /srv/www/
# Allow PHP-FPM (UID 65532) to write uploaded media
RUN chown -R 65532:65532 /srv/www/wp-contentOn first boot, navigating to your site triggers the WordPress setup wizard, which creates the database tables and sets your admin credentials. After that, WordPress is fully operational.
Step 3: Configure Podman Quadlets for service management
Podman Quadlets let you define your containers as systemd service units. Each of the three containers—Apache, PHP-FPM, and MariaDB—gets a .container unit file that tells systemd how to run it, what network it belongs to, what secrets to inject, and what it depends on.
The result is that your containers start automatically at boot, restart on failure, and log through the standard journald pipeline. No container orchestration platform required. Standard Linux service management, extended to containers.
This is also where you configure the shared Podman network that lets PHP-FPM reach MariaDB by hostname (mariadb), and where you wire in the database password secret so it never touches the image filesystem.
Step 4: Package everything into a single bootable image
With the application layer complete and services defined, you use bootc-image-builder to assemble the whole thing into a bootable disk image. The image contains:
- The RHEL 10 OS layer from the Red Hat Hardened Images base
- Your WordPress files at
/srv/www, mounted into the Apache and PHP-FPM containers at runtime - Your Podman Quadlet unit files for all three services
- References to the Red Hat Hardened Images for Apache, PHP-FPM, and MariaDB, pre-fetched as logically bound images
The artifact you produce is not a provisioning script or a runbook. It is the entire system state, frozen and versioned. Anyone with access to your Containerfile can reproduce the same image. Any environment you deploy it to gets the same system.
Step 5: Boot it as a virtual machine
Deploy the image to a virtual machine (VM)—on-premises, in a private cloud, wherever your infrastructure lives. When systemd starts, the Quadlets bring up MariaDB first, then Apache and PHP once the database is ready. WordPress is available.
The same image runs on your development machine, your staging environment, and production. The behavior is identical because the artifact is identical.
What you end up with
A WordPress deployment where:
- The attack surface is dramatically smaller than a general-purpose LAMP installation—fewer packages, fewer CVE alerts, less noise.
- The environment is fully reproducible from source. Commit your Containerfile and Quadlet units, anyone can build it.
- The running system is less likely to drift from what you shipped—no undocumented manual changes, no configuration divergence between environments.
- Updates are image releases—build, test, deploy, roll back if needed—the same workflow you already use for application code.
- The foundation is Red Hat Enterprise Linux 10 with Red Hat Hardened Images—backed by Red Hat's security and support commitments.
Why run your own instead of buying managed hosting?
Managed WordPress hosting is easy. You sign up, you get a URL, WordPress is running. So why would a developer choose to build and operate it themselves?
Your plug-ins, your rules
Managed hosts restrict what you can install. Security plug-ins, custom PHP extensions, non-standard caching layers—they get blocked because they are incompatible with the host's shared infrastructure. On your own stack, you decide.
Your data, your jurisdiction
Compliance requirements—HIPAA, GDPR, internal data residency policies—often mean your content database cannot live on someone else's shared infrastructure. Running your own gives you control over exactly where data is stored and who can access it.
Your environment matches your app
When WordPress is running on the same infrastructure as the rest of your stack, it's straightfoward to integrate it with your network policies, auth provider, your internal APIs, your observability tools, and so on.
Cost structure makes sense at scale
Managed hosting fees compound with traffic and storage. A well-built self-hosted deployment on your own infrastructure often becomes significantly cheaper once you are running at any meaningful scale.
The security trade-off in your favor
On shared infrastructure, you're bound by the security posture of the weakest tenant. On your own stack—especially one built on Red Hat Hardened Images—you control the attack surface. And that attack surface can be made substantially smaller than anything a general-purpose shared host offers.
Practical benefits for developers
Running WordPress on this stack does not just make the security team happy. It solves concrete developer problems.
You stop getting woken up about CVEs in packages that have nothing to do with your workload. Your staging environment actually matches production, so the "worked on my machine" problem largely disappears. Deploying an update means building a new image and rolling it out—the same mental model you use for everything else in a container-based workflow.
The hardened foundation is not overhead. It's the thing that gives you back time, and it's just one learning path away. Build it, drop WordPress in, and deploy.
Learn more about Red Hat Hardened Images and image mode for RHEL.