Running WordPress with Docker Compose gives you a reproducible, portable environment that is easy to spin up for local development or small deployments. In this article, we will build a minimal but robust setup that uses WordPress with MariaDB, including persistent storage and a proper health check using MariaDB’s built-in healthcheck.sh script.

Overview of the architecture

Our stack consists of two containers on the same Docker network: a MariaDB container as the database and a WordPress container running Apache and PHP 8.2. We add named volumes for persistence, environment variables for configuration, and a health check on MariaDB so WordPress waits for a fully initialized InnoDB engine before attempting to connect.

The docker-compose.yml

Below is the full docker-compose.yml that works with current MariaDB and WordPress images:

version: "3.9"

services:
  db:
    image: mariadb:11.3
    container_name: wordpress-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_password
      MYSQL_ROOT_PASSWORD: root_password
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 60s

  wordpress:
    image: wordpress:php8.2-apache
    container_name: wordpress-app
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress_password
      WORDPRESS_DB_NAME: wordpress
    ports:
      - "8080:80"
    volumes:
      - wordpress_data:/var/www/html

volumes:
  db_data:
  wordpress_data:

This configuration keeps the database and WordPress state in named volumes and wires WordPress to wait for a healthy MariaDB instance using the official health check script.

Service: MariaDB (db)

The db service defines the MariaDB database container and uses the official MariaDB image with its integrated health check script.

Key aspects:

  • image: mariadb:11.3 pins a recent stable MariaDB release, which helps keep behavior consistent and avoids surprises from latest. environment sets up the initial database: MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD, and MYSQL_ROOT_PASSWORD are read by the entrypoint to create the schema and users on first run.
  • volumes: - db_data:/var/lib/mysql stores the MariaDB data directory in a named volume so your data persists across container recreations and upgrades.

The health check is where this service becomes more robust:

healthcheck:
  test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
  interval: 10s
  timeout: 5s
  retries: 5
  start_period: 60s
  • healthcheck.sh is a script shipped in the MariaDB official Docker image specifically for health monitoring and supports multiple tests.
  • --connect verifies that a client can successfully connect to the server using the dedicated healthcheck user created by the image.
  • --innodb_initialized ensures that the InnoDB storage engine has finished initialization, preventing false positives during the initial database bootstrap.
  • start_period: 60s gives MariaDB extra time to initialize before failed checks count against the retries limit, which is useful for first startup on larger or slower disks.

This approach is more accurate than using mysqladmin ping, which can report success even while initialization or upgrade routines are still running.

Service: WordPress (wordpress)

The wordpress service defines the application container that runs WordPress on Apache with PHP 8.2.

Important points:

  • image: wordpress:php8.2-apache uses the official WordPress image variant that bundles Apache and PHP 8.2, giving you a maintained, up-to-date runtime.
  • depends_on: db: condition: service_healthy tells Docker Compose not just to start containers in order, but to wait until MariaDB’s health check passes, which avoids race conditions at startup.
  • The database environment variables (WORDPRESS_DB_HOST, WORDPRESS_DB_USER, WORDPRESS_DB_PASSWORD, WORDPRESS_DB_NAME) mirror the MariaDB configuration and instruct WordPress how to connect to the database over the internal Docker network.
  • ports: "8080:80" publishes WordPress on port 8080 of your host so you can access it at http://localhost:8080.
  • volumes: - wordpress_data:/var/www/html keeps the WordPress core, plugins, themes, and uploads persistent in a named volume, which protects content and configuration from container lifecycle changes.

This container design keeps WordPress stateless from the perspective of the image and pushes state into Docker-managed volumes, which aligns well with container best practices.

Volumes: persistence layer

The volumes section declares two named volumes used by the services:

volumes:
  db_data:
  wordpress_data:
  • db_data holds the MariaDB data directory, which contains all databases defined by your instance.
  • wordpress_data holds the WordPress application files and uploaded media, including themes and plugins.

Named volumes are managed by Docker and are not removed by a plain docker compose down, which means your data survives service restarts and configuration tweaks. If you explicitly run docker compose down --volumes, Docker will remove these volumes and you will lose the database and WordPress content.

Running and managing the stack

To bring this stack up:

  1. Create a directory (for example, wordpress-stack) and save the YAML above as docker-compose.yml in it.

  2. Edit the environment values for passwords and database names to suit your environment and security policies, ideally moving them into an .env file.

  3. From that directory, start the stack in detached mode:

    docker compose up -d
  4. Wait for the containers to reach a healthy state, then open:

    http://localhost:8080

    and complete the WordPress installation wizard.

To stop the stack while preserving data:

docker compose down

To completely tear down including volumes and stored data:

docker compose down --volumes

This workflow gives you a repeatable, self-contained WordPress + MariaDB environment that starts reliably, thanks to the health-checked database service.