{"id":2120,"date":"2026-02-14T01:50:47","date_gmt":"2026-02-13T12:50:47","guid":{"rendered":"https:\/\/www.ronella.xyz\/?p=2120"},"modified":"2026-02-14T01:51:07","modified_gmt":"2026-02-13T12:51:07","slug":"running-wordpress-and-mariadb-with-docker-compose","status":"publish","type":"post","link":"https:\/\/www.ronella.xyz\/?p=2120","title":{"rendered":"Running WordPress and MariaDB with Docker Compose"},"content":{"rendered":"<p>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\u2019s built-in <code>healthcheck.sh<\/code> script.<\/p>\n<h2>Overview of the architecture<\/h2>\n<p>Our stack consists of two containers on the same Docker network: a <strong>MariaDB<\/strong> container as the database and a <strong>WordPress<\/strong> 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.<\/p>\n<h2>The docker-compose.yml<\/h2>\n<p>Below is the full <code>docker-compose.yml<\/code> that works with current MariaDB and WordPress images:<\/p>\n<pre><code class=\"language-yaml\">version: &quot;3.9&quot;\n\nservices:\n  db:\n    image: mariadb:11.3\n    container_name: wordpress-db\n    restart: unless-stopped\n    environment:\n      MYSQL_DATABASE: wordpress\n      MYSQL_USER: wordpress\n      MYSQL_PASSWORD: wordpress_password\n      MYSQL_ROOT_PASSWORD: root_password\n    volumes:\n      - db_data:\/var\/lib\/mysql\n    healthcheck:\n      test: [&quot;CMD&quot;, &quot;healthcheck.sh&quot;, &quot;--connect&quot;, &quot;--innodb_initialized&quot;]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n      start_period: 60s\n\n  wordpress:\n    image: wordpress:php8.2-apache\n    container_name: wordpress-app\n    depends_on:\n      db:\n        condition: service_healthy\n    restart: unless-stopped\n    environment:\n      WORDPRESS_DB_HOST: db:3306\n      WORDPRESS_DB_USER: wordpress\n      WORDPRESS_DB_PASSWORD: wordpress_password\n      WORDPRESS_DB_NAME: wordpress\n    ports:\n      - &quot;8080:80&quot;\n    volumes:\n      - wordpress_data:\/var\/www\/html\n\nvolumes:\n  db_data:\n  wordpress_data:<\/code><\/pre>\n<p>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.<\/p>\n<h2>Service: MariaDB (db)<\/h2>\n<p>The <code>db<\/code> service defines the MariaDB database container and uses the official MariaDB image with its integrated health check script.<\/p>\n<p>Key aspects:<\/p>\n<ul>\n<li><code>image: mariadb:11.3<\/code> pins a recent stable MariaDB release, which helps keep behavior consistent and avoids surprises from <code>latest<\/code>. <code>environment<\/code> sets up the initial database: <code>MYSQL_DATABASE<\/code>, <code>MYSQL_USER<\/code>, <code>MYSQL_PASSWORD<\/code>, and <code>MYSQL_ROOT_PASSWORD<\/code> are read by the entrypoint to create the schema and users on first run. <\/li>\n<li><code>volumes: - db_data:\/var\/lib\/mysql<\/code> stores the MariaDB data directory in a named volume so your data persists across container recreations and upgrades.<\/li>\n<\/ul>\n<p>The health check is where this service becomes more robust:<\/p>\n<pre><code class=\"language-yaml\">healthcheck:\n  test: [&quot;CMD&quot;, &quot;healthcheck.sh&quot;, &quot;--connect&quot;, &quot;--innodb_initialized&quot;]\n  interval: 10s\n  timeout: 5s\n  retries: 5\n  start_period: 60s<\/code><\/pre>\n<ul>\n<li><code>healthcheck.sh<\/code> is a script shipped in the MariaDB official Docker image specifically for health monitoring and supports multiple tests.<\/li>\n<li><code>--connect<\/code> verifies that a client can successfully connect to the server using the dedicated healthcheck user created by the image.<\/li>\n<li><code>--innodb_initialized<\/code> ensures that the InnoDB storage engine has finished initialization, preventing false positives during the initial database bootstrap.<\/li>\n<li><code>start_period: 60s<\/code> gives MariaDB extra time to initialize before failed checks count against the <code>retries<\/code> limit, which is useful for first startup on larger or slower disks.<\/li>\n<\/ul>\n<p>This approach is more accurate than using <code>mysqladmin ping<\/code>, which can report success even while initialization or upgrade routines are still running.<\/p>\n<h2>Service: WordPress (wordpress)<\/h2>\n<p>The <code>wordpress<\/code> service defines the application container that runs WordPress on Apache with PHP 8.2. <\/p>\n<p>Important points:<\/p>\n<ul>\n<li><code>image: wordpress:php8.2-apache<\/code> uses the official WordPress image variant that bundles Apache and PHP 8.2, giving you a maintained, up-to-date runtime.<\/li>\n<li><code>depends_on: db: condition: service_healthy<\/code> tells Docker Compose not just to start containers in order, but to wait until MariaDB\u2019s health check passes, which avoids race conditions at startup.<\/li>\n<li>The database environment variables (<code>WORDPRESS_DB_HOST<\/code>, <code>WORDPRESS_DB_USER<\/code>, <code>WORDPRESS_DB_PASSWORD<\/code>, <code>WORDPRESS_DB_NAME<\/code>) mirror the MariaDB configuration and instruct WordPress how to connect to the database over the internal Docker network.<\/li>\n<li><code>ports: &quot;8080:80&quot;<\/code> publishes WordPress on port 8080 of your host so you can access it at <code>http:\/\/localhost:8080<\/code>.<\/li>\n<li><code>volumes: - wordpress_data:\/var\/www\/html<\/code> keeps the WordPress core, plugins, themes, and uploads persistent in a named volume, which protects content and configuration from container lifecycle changes.<\/li>\n<\/ul>\n<p>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.<\/p>\n<h2>Volumes: persistence layer<\/h2>\n<p>The <code>volumes<\/code> section declares two named volumes used by the services:<\/p>\n<pre><code class=\"language-yaml\">volumes:\n  db_data:\n  wordpress_data:<\/code><\/pre>\n<ul>\n<li><code>db_data<\/code> holds the MariaDB data directory, which contains all databases defined by your instance.<\/li>\n<li><code>wordpress_data<\/code> holds the WordPress application files and uploaded media, including themes and plugins.<\/li>\n<\/ul>\n<p>Named volumes are managed by Docker and are not removed by a plain <code>docker compose down<\/code>, which means your data survives service restarts and configuration tweaks.  If you explicitly run <code>docker compose down --volumes<\/code>, Docker will remove these volumes and you will lose the database and WordPress content.<\/p>\n<h2>Running and managing the stack<\/h2>\n<p>To bring this stack up:<\/p>\n<ol>\n<li>\n<p>Create a directory (for example, <code>wordpress-stack<\/code>) and save the YAML above as <code>docker-compose.yml<\/code> in it.<\/p>\n<\/li>\n<li>\n<p>Edit the environment values for passwords and database names to suit your environment and security policies, ideally moving them into an <code>.env<\/code> file.<\/p>\n<\/li>\n<li>\n<p>From that directory, start the stack in detached mode:<\/p>\n<pre><code class=\"language-bash\">docker compose up -d<\/code><\/pre>\n<\/li>\n<li>\n<p>Wait for the containers to reach a healthy state, then open:<\/p>\n<pre><code class=\"language-text\">http:\/\/localhost:8080<\/code><\/pre>\n<p>and complete the WordPress installation wizard.<\/p>\n<\/li>\n<\/ol>\n<p>To stop the stack while preserving data:<\/p>\n<pre><code class=\"language-bash\">docker compose down<\/code><\/pre>\n<p>To completely tear down including volumes and stored data:<\/p>\n<pre><code class=\"language-bash\">docker compose down --volumes<\/code><\/pre>\n<p>This workflow gives you a repeatable, self-contained WordPress + MariaDB environment that starts reliably, thanks to the health-checked database service.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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\u2019s built-in healthcheck.sh script. Overview of the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[78],"tags":[],"_links":{"self":[{"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/posts\/2120"}],"collection":[{"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2120"}],"version-history":[{"count":1,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/posts\/2120\/revisions"}],"predecessor-version":[{"id":2121,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=\/wp\/v2\/posts\/2120\/revisions\/2121"}],"wp:attachment":[{"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ronella.xyz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}