Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk14 min

How to Run WordPress in Docker Containers and Kubernetes Clusters

Deploy WordPress safely with Docker Compose, then understand the storage, database, networking, and recovery work required to move it to Kubernetes.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run WordPress on one machine with Docker Compose: one WordPress container, one MariaDB or MySQL container, and named volumes for both the database and /var/www/html. Move to Kubernetes only when you need cluster scheduling or rescheduling; then use Services, PersistentVolumeClaims, durable database storage, and an explicit plan for uploads, backups, ingress, and TLS. Containers can be replaced at any time, so persistence and recovery—not the image itself—determine whether the site is safe.

What a containerized WordPress installation contains

WordPress has two different kinds of state. Posts, pages, users, settings, and plugin data live in a relational database. Themes, plugins, WordPress core files, and uploaded media live in the filesystem, especially wp-content/uploads. A container’s writable layer is disposable: Docker or a cluster may remove the container, recreate it, evict it, or schedule a replacement elsewhere. Keeping either state only in that layer eventually loses it.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A practical deployment therefore separates responsibilities:

  • WordPress service: serves PHP and web requests.
  • Database service: stores relational content and configuration.
  • Persistent storage: keeps database files and WordPress files outside replaceable containers.
  • Network and service discovery: lets WordPress reach the database without exposing the database publicly.
  • Secrets: supplies passwords without placing them in ordinary configuration or source control.

Compose provides those building blocks on one host. Kubernetes adds scheduling, Services, PersistentVolumes (PVs), PersistentVolumeClaims (PVCs), controllers, and cluster-wide operations; it does not automatically make the database highly available or WordPress horizontally scalable.

Choose the deployment scope first

Question Docker Compose Kubernetes
Where does it run? One Docker host or virtual machine. A cluster that can schedule workloads on multiple nodes.
Persistence primitive Named Docker volumes, bind mounts, or an external volume driver. PVs and PVCs backed by a storage class, managed disk, or another durable system.
Failure behavior Containers restart on the same host unless you replace the host or volume. Pods can be rescheduled to another node, provided storage can attach there.
Service exposure Host port mapping or a reverse proxy on the host. ClusterIP, LoadBalancer, or Ingress, normally with a TLS controller.
Scaling Useful for development and a single-site host; no cluster scheduler. Can run multiple WordPress Pods, but only after shared media, session behavior, and database capacity are designed.
Secrets Compose secrets and the image’s _FILE variables. Kubernetes Secrets, an external secret manager, and controlled Pod access.
Operations You manage updates, host failure, backups, and recovery directly. You also manage storage classes, scheduling, ingress, observability, upgrades, and recovery across the cluster.

For a laptop, test server, or one production host, start with Compose. Kubernetes is justified when the team can operate the additional storage, networking, database, and recovery machinery, not simply because a container image exists.

Prerequisites and decisions before starting

  • Install Docker Engine and the Docker Compose plugin on the host, and confirm that docker compose version works.
  • Choose image tags that you have tested together. Pin those tags, or better, immutable digests; do not rely on an unreviewed moving latest tag.
  • Decide where the host will keep database and WordPress volumes, how they will be backed up, and how a replacement host would obtain them.
  • Keep the database on an internal network. Publish only the web service’s port.
  • Store database passwords in secret files or a secret manager. Add local secret files to .gitignore and restrict their filesystem permissions.
  • Plan DNS, HTTPS termination, email delivery, updates, and monitoring before calling the installation production-ready.

Run WordPress with Docker Compose

Create a project and secret files

Create a directory for the deployment, then make a secrets subdirectory. Put a separate, long random value in each file:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
mkdir -p wordpress-docker/secrets
cd wordpress-docker
printf '%s' 'replace-with-a-random-database-password' > secrets/db_password.txt
printf '%s' 'replace-with-a-different-root-password' > secrets/db_root_password.txt
chmod 600 secrets/*.txt

The values above are deliberately examples; generate real passwords with a password manager or operating-system random source, and never commit the files.

Define the services, networks, volumes, and secrets

Save the following as compose.yaml. The image variables make the versions explicit in your environment; set them to tags that you have tested and approved.

services:
  db:
    image: ${DB_IMAGE}
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: wordpress
      MARIADB_USER: wordpress
      MARIADB_PASSWORD_FILE: /run/secrets/db_password
      MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
    secrets:
      - db_password
      - db_root_password
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - backend

  wordpress:
    image: ${WORDPRESS_IMAGE}
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - wp_data:/var/www/html
    networks:
      - backend
      - frontend

networks:
  frontend:
  backend:
    internal: true

volumes:
  db_data:
  wp_data:

secrets:
  db_password:
    file: ./secrets/db_password.txt
  db_root_password:
    file: ./secrets/db_root_password.txt

Set DB_IMAGE and WORDPRESS_IMAGE in a local .env file or export them in the shell. Verify the final configuration before starting:

docker compose config

Compose models services, networks, volumes, configs, and secrets separately. The backend network is marked internal, so the database is reachable by the service name db but is not published on a host port.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Start the site and complete the installer

  1. Start both services in the background: docker compose up -d.
  2. Check container status with docker compose ps.
  3. Follow startup output with docker compose logs -f wordpress db. The database may take a short time to initialize on its first run.
  4. Open http://localhost:8080 (or the host’s DNS name) and complete the WordPress web installer.
  5. Confirm that a test post, an image upload, and a plugin activation survive a restart.

In a real deployment, put a reverse proxy or load balancer in front of the application, terminate HTTPS there, and avoid exposing the raw development port directly to the public internet.

Understand what stopping and deleting does

docker compose down removes the containers and the default network while preserving the named volumes. The database and WordPress files therefore remain available when you run docker compose up -d again. Adding --volumes removes the named volumes as well:

docker compose down --volumes

That command deletes the stored database and WordPress data. Treat it as a destructive operation and require a verified backup before using it.

Make the Compose deployment safer

Keep credentials out of ordinary environment values

The official WordPress image supports _FILE variants for supported settings, allowing the entrypoint to read a value from a mounted secret file. Use that mechanism, Compose secrets, or an external secret store rather than placing passwords in a committed YAML file. Secret files still need host-level protection and backup handling; a secret mounted into a container is not a substitute for access control.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reduce writable paths when the application permits it

A hardened pattern runs the WordPress container with a read-only root filesystem and supplies writable temporary paths such as /tmp and /run. If the site accepts media, mount only the required uploads directory, commonly /var/www/html/wp-content/uploads, as writable persistent storage. Test updates, image processing, caching, and plugins first: some extensions write outside those paths. You may need a controlled maintenance deployment with broader write access for core, theme, or plugin updates.

Update images deliberately

Container images do not update themselves. Review security releases, pull the new tested tag or digest, recreate the services, and watch logs and health checks. Keep a database dump and a copy of the WordPress volume before upgrades. A repeatable rebuild-and-redeploy process is safer than modifying a running container by hand.

Back up both kinds of state

A database dump alone cannot restore uploaded media, and a file archive alone cannot restore posts or settings. Schedule both, store copies outside the Docker host, encrypt them, retain multiple restore points, and periodically perform a restoration on an isolated environment. A backup is only useful when the team can restore it within the required time.

For a logical database backup, run a client inside the database container so the host does not need a matching client version:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
docker compose exec -T db mariadb-dump -u root -p wordpress > wordpress-$(date +%F).sql

The command prompts for the root password. Archive the wp_data volume with a temporary helper container or your volume driver’s snapshot facility, and document the exact restore procedure. Do not copy a live database directory as if it were a consistent backup.

Move WordPress to Kubernetes

Map Compose concepts to Kubernetes

  • A Compose service becomes a Deployment or StatefulSet plus a Service.
  • A named volume becomes a PVC bound to a PV supplied by a storage class or administrator.
  • Compose’s internal network becomes Kubernetes network policy and Service DNS; the database can be addressed by its Service name.
  • Port publishing becomes a Service type and, for HTTP, commonly an Ingress.
  • Compose secrets become Kubernetes Secrets or an external secret integration.

Kubernetes documentation’s basic WordPress and MySQL example is explicitly educational: it is not suitable for production because it uses single-instance WordPress and MySQL Pods. Use it to learn object relationships, not as a high-availability design.

Provide durable claims before creating Pods

A PVC requests storage independently of a Pod. When a Pod restarts, is deleted, or is rescheduled, the claim can be mounted again and the data remains, subject to the storage system’s retention and reclaim policy. A typical learning setup creates one claim for the database and one for WordPress files:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-data
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

The sizes are examples, not universal requirements. Choose capacity from the site’s database, media, temporary files, backups, and growth. If the cluster has no default storage class, an administrator must provide a matching PV or configure a provisioner. A ReadWriteOnce claim normally attaches to one node at a time; it is not shared media storage for several WordPress Pods.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a database workload and credentials

Store credentials in a Kubernetes Secret rather than in a Deployment manifest. The following is a minimal teaching example; use your platform’s secret manager and a managed or replicated database for important sites.

apiVersion: v1
kind: Secret
metadata:
  name: wordpress-db
stringData:
  database: wordpress
  user: wordpress
  password: replace-with-a-random-password
  root-password: replace-with-a-different-random-password
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  selector:
    app: mysql
  ports:
    - port: 3306
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_DATABASE
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: database
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: user
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: password
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: root-password
          volumeMounts:
            - name: database-data
              mountPath: /var/lib/mysql
      volumes:
        - name: database-data
          persistentVolumeClaim:
            claimName: database-data

Pin a database image that your team has tested; the example tag is not a recommendation for every site. A single database Pod still has a single failure domain, even though its files are persistent.

Deploy WordPress and expose it internally

apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  selector:
    app: wordpress
  ports:
    - port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wordpress
  template:
    metadata:
      labels:
        app: wordpress
    spec:
      containers:
        - name: wordpress
          image: wordpress:php8.3-apache
          env:
            - name: WORDPRESS_DB_HOST
              value: mysql:3306
            - name: WORDPRESS_DB_NAME
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: database
            - name: WORDPRESS_DB_USER
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: user
            - name: WORDPRESS_DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: wordpress-db
                  key: password
          volumeMounts:
            - name: wordpress-data
              mountPath: /var/www/html
      volumes:
        - name: wordpress-data
          persistentVolumeClaim:
            claimName: wordpress-data

Apply the manifests and inspect scheduling, claims, and events:

kubectl apply -f wordpress.yaml
kubectl get pods,pvc,svc
kubectl describe pod -l app=wordpress
kubectl logs deploy/wordpress

For public traffic, add an Ingress that targets the wordpress Service and configure a TLS certificate through the cluster’s certificate solution. A Service by itself does not provide a public DNS name or HTTPS.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a second WordPress Pod is not automatic scaling

Running two or more replicas helps only after every shared dependency is addressed:

  • Media: every replica must see the same uploads. Use a storage system that supports the required multi-node access mode or move media to object storage and configure WordPress accordingly.
  • Code: build one tested image containing the same core, themes, and plugins for every replica. Do not let replicas drift through ad-hoc in-container edits.
  • Database: replicas still write to one database. Database replication, failover, backups, and connection limits require their own design; adding web Pods does not create database availability.
  • Sessions and cache: evaluate login sessions, page caching, and object caching. Redis can provide a shared object-cache layer, but it also needs persistence, security, and failure handling.
  • Traffic: use an Ingress or load balancer and configure readiness probes so traffic reaches only ready Pods.

WordPress core, themes, and plugins can be treated as stateless application code only when uploads and other mutable data have been externalized. Autoscaling should respond to measured CPU, memory, request, or queue pressure and should be tested against database and storage limits.

Storage choices and node behavior

Managed or portable network storage

A dynamically provisioned volume can follow a Pod between nodes when the storage platform supports that operation. Confirm attachment limits, performance, snapshots, access modes, reclaim policy, encryption, and regional failure behavior with the platform operator. Persistent storage protects data from Pod lifecycles; it does not by itself create a backup.

Local volumes

A local PV is tied to a particular node and requires node affinity. It can be useful for learning or a constrained installation, but a replacement Pod scheduled on another node cannot use that data unless the node returns or the data is copied elsewhere. Local storage is therefore not portable storage and should not be mistaken for cluster-wide durability.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Object storage for media

As a site grows across nodes or regions, object storage can remove the shared-filesystem bottleneck for images and other uploads. It introduces its own credentials, lifecycle rules, latency, egress costs, and restore process. Keep the WordPress database and media backup plans coordinated so a restored database does not point to missing files.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Production checklist for a cluster

  1. Use a managed or deliberately replicated database, with tested point-in-time or scheduled backups and a documented failover procedure.
  2. Provision durable, encrypted storage for any state that remains on volumes; define reclaim and deletion behavior explicitly.
  3. Build immutable WordPress images and keep core, themes, and plugins at known versions.
  4. Externalize media when multiple Pods or nodes require shared access.
  5. Use Kubernetes Secrets or an external secret manager, restrict RBAC access, and rotate credentials.
  6. Expose HTTP through an Ingress or load balancer with TLS, redirect plain HTTP where appropriate, and renew certificates automatically.
  7. Add readiness and liveness checks, resource requests and limits, centralized logs, metrics, and alerts for storage, database health, and failed backups.
  8. Test rolling updates, plugin changes, database schema migrations, node loss, storage loss, and a complete restore in a non-production environment.
  9. Document who can perform an emergency rollback and where the required image, manifest, secret, and backup versions are stored.

Upgrade and recovery procedures

Compose upgrade

  1. Export a consistent database backup and archive or snapshot the WordPress volume.
  2. Change the pinned image tag or digest in the environment file.
  3. Run docker compose pull, then docker compose up -d to recreate only what changed.
  4. Watch docker compose logs, verify the site, log in, upload a test image, and check scheduled tasks.
  5. If the release fails, restore the previous image and follow the documented database rollback plan; never assume an application image rollback reverses a database migration.

Kubernetes upgrade

  1. Back up the database and confirm that the backup can be restored.
  2. Publish the new immutable WordPress image and update the Deployment.
  3. Use a rolling strategy with readiness probes so an unready Pod receives no traffic.
  4. Monitor Pod events, application logs, database connections, PVC health, and ingress responses.
  5. Roll back the Deployment image when the application is incompatible, while treating irreversible database migrations as a separate change that needs its own recovery plan.

Recover after a lost Pod

Do not copy files out of a dead container and expect them to be permanent. Recreate the Pod with the same claim. If the claim is unavailable, restore the database backup and WordPress files to new durable storage, then point the workloads at those restored claims. Verify URLs, permissions, uploads, scheduled jobs, and administrator access before reopening traffic.

Troubleshooting common failures

Symptom Likely cause Action
WordPress reports a database connection error. The database is still initializing, the host name is wrong, or credentials differ between services. Check service or Pod logs, confirm the database Service name and port, inspect secret keys, and wait for a healthy database before restarting WordPress.
The site loses posts after a restart. The database directory was not mounted to durable storage, or a destructive volume command was used. Inspect mounts and PVC bindings, stop further writes, and restore the latest verified database backup.
Uploaded images disappear on another Pod. Each replica has its own local filesystem. Use shared durable storage or object storage, and ensure every replica uses the same upload configuration.
A Pod is pending indefinitely. No matching PV, unavailable storage class, node affinity conflict, or insufficient cluster capacity. Use kubectl describe pod and kubectl describe pvc; fix the storage or scheduling constraint rather than deleting the claim.
HTTPS works intermittently or not at all. Ingress, DNS, certificate, or Service target configuration is wrong. Check the Ingress events, certificate status, DNS record, backend Service endpoints, and TLS secret.
An image update breaks plugins. PHP, WordPress, or plugin compatibility changed. Pin the last known-good image, restore if necessary, test the combination in staging, and upgrade dependencies deliberately.

Compose or Kubernetes: a practical decision

Choose Compose when one host is an acceptable failure domain, the site has modest operational needs, and you want a short path from an empty directory to a working installation. Named volumes, secret files, regular image rebuilds, and off-host backups provide a sound baseline.

Choose Kubernetes when you need cluster scheduling, controlled rescheduling, multiple application replicas, or integration with an existing platform team. Budget for storage provisioning, database availability, shared media, ingress and certificates, observability, upgrades, and recovery drills. Those are separate engineering tasks; placing the same image in a Pod does not complete them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently asked questions

Can WordPress run without a database container?

WordPress requires a compatible relational database. The database can run in the same Compose project, on a managed service, or elsewhere in the network, but it still needs durable storage, credentials, backups, and a tested recovery path.

Will deleting a Kubernetes Pod delete my WordPress data?

Not when the data is on a correctly bound PVC and the underlying storage has retained it. Pod deletion and storage deletion are different operations. Confirm the claim’s reclaim policy and test restoration before relying on that behavior.

Is a local Kubernetes volume acceptable for production?

Only when the site’s failure requirements explicitly accept node affinity and the operator has a separate, tested copy of the data. Local volumes do not follow a Pod to another node by themselves.

How do I migrate from Compose to Kubernetes?

Back up the database and WordPress files, build a reproducible image, provision PVCs or external storage, create database and WordPress workloads, restore the data, test the site through an internal Service, and switch DNS or ingress only after uploads, scheduled jobs, plugins, and rollback have been verified.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

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

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.