How to Use Docker for Local WordPress Development: Complete Step-by-Step Guide

How to Use Docker for Local WordPress Development: Complete Step-by-Step Guide
How to Use Docker for Local WordPress Development: Complete Step-by-Step Guide

Learn how to build a local WordPress development environment with Docker and Docker Compose. This step-by-step guide helps you streamline setup, improve workflows, and mirror production with ease.

You clone a project, spin it up, and it runs. A teammate clones the same project and it falls over. Different PHP version, a MySQL they don’t have, a missing extension. That gap between “works on my machine” and “works on yours” is exactly what Docker was built to close. It packages WordPress and its database into isolated containers that behave the same wherever they run, so your local setup stops drifting away from everyone else’s and from production. In this guide we’ll build a working local WordPress site with Docker and Docker Compose, then look at what changes when you carry those ideas toward production.

Table of Contents

Prerequisites: Getting Docker Ready

Before you start, you’ll want:

  • Docker Desktop on Mac or Windows, or Docker Engine on Linux. Docker Compose now ships built in as the docker compose command, so you get it with either install. Follow the official Docker installation guide for your platform.
  • Enough comfort with WordPress and the command line to run a few commands and edit a file.

One naming note up front, because it trips people up. The modern command is docker compose, with a space. The older standalone tool was docker-compose, with a hyphen, and it reached end of life in 2023. Everything here uses the space form. If you’re on an older box that only has the hyphen version, the commands still work the same way.

Docker Compose: Orchestrating Your WordPress Environment

A WordPress site is really two moving parts: the application and a database. Compose lets you describe both in one file and run them together. We’ll write a docker-compose.yml that defines a WordPress service and a MySQL (or MariaDB) service, and Compose wires them up on a shared network so they can talk to each other by name.

Step-by-Step: Crafting Your docker-compose.yml

Create a file named docker-compose.yml in your project directory and paste in the following. It uses MySQL 8.0 for the database.

HTML
version: '3.8'
services:
  db:
    image: mysql:8.0
    container_name: wp_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspassword
    volumes:
      - db_data:/var/lib/mysql
  wordpress:
    image: wordpress:latest
    container_name: wp_site
    depends_on:
      - db
    restart: always
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspassword
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp-content:/var/www/html/wp-content
volumes:
  db_data:

One thing to know about that first line. The top-level version key is now obsolete under the current Compose specification. Compose v2 ignores it and will print a warning telling you it’s no longer needed. It’s harmless to leave in and just as safe to delete. New files skip it entirely.

Configuring the Database and WordPress Services

Here’s what each piece of that file is doing:

  • Database service: Runs the official MySQL 8.0 image. The environment variables set the root password and create the application database and user on first boot. The named volume (db_data) is where the actual data lives, so it survives restarts.
  • WordPress service: Runs the official WordPress image and maps container port 80 to host port 8080, which is how you reach it in a browser. It reads the database connection from those WORDPRESS_DB_* variables, and it mounts your local ./wp-content into the container so you can edit themes and plugins right on your machine.
  • Volumes: The named db_data volume keeps your database intact between up and down cycles. Without it, every teardown would wipe your content.

About depends_on: it controls start order, so the db container launches before WordPress. It does not wait for MySQL to be ready to accept connections, only for the container to start. In practice WordPress retries the connection, so this usually just works. If you hit a race on a slow machine, add a healthcheck to the db service and depend on condition: service_healthy.

Launching and Managing Your Containers

With the file saved, these are the commands you’ll actually use day to day:

  • Start: docker compose up -d runs the containers in the background.
  • Stop and remove: docker compose down (add -v only when you also want to delete the database volume).
  • List running containers: docker compose ps
  • Follow logs: docker compose logs -f wordpress
  • Open a shell inside a container: docker compose exec wordpress bash

Once it’s up, open http://localhost:8080 and you’ll get the WordPress installer.

The Local Development Workflow: Code, WP-CLI, Databases

The setup pays off in the day-to-day loop:

  • Editing code: Because ./wp-content is mounted from your machine, you edit theme and plugin files in your normal editor and the changes show up in the container immediately. No copying, no rebuild.
  • WP-CLI: The official WordPress image already includes WP-CLI, so run it straight inside the container.

    Example: docker compose exec wordpress wp plugin install jetpack --activate
  • Database: Your data persists in the db_data volume. For imports and exports, reach for WP-CLI (wp db export / wp db import), or add phpMyAdmin as an extra service if you’d rather click around.

[Optional] Bridging the Gap: Docker Concepts for Production

This guide is about local development, but the same building blocks stretch toward production if you ever go that way:

  • Custom Dockerfiles: For production you’d usually write a Dockerfile that bakes in the PHP extensions, themes, and plugins you need, so the image is self-contained instead of relying on mounted folders.
  • Volume mounts vs. image builds: Local development leans on volume mounts for fast iteration. Production does the opposite: your code gets copied into the image at build time, so what you test is exactly what you ship.
  • Orchestration: Once you’re running more than one host, tools like Kubernetes or Docker Swarm, or a Docker-friendly host, handle scaling, rolling updates, and secrets. That’s a bigger topic than one WordPress box, so treat it as the next mountain, not part of this one.
Example: A Simple Production Dockerfile
HTML
FROM wordpress:latest
# Copy your theme/plugin files into the image
COPY wp-content /var/www/html/wp-content
# Set non-root user and optimize the image
USER www-data
# Expose port 80
EXPOSE 80
CMD ["apache2-foreground"]

That’s a bare-bones starting point. A real production image would pin exact versions and handle secrets outside the file rather than in plain environment variables, but it shows the shape: copy your code in, run as a non-root user, serve on port 80.

Common Pitfalls & Troubleshooting Tips

  • Port conflicts: If up fails complaining about a port, something else is already on host port 8080. Change the left side of the mapping (for example 8081:80) and try again.
  • Volume permissions: Mounted local folders can hit ownership mismatches, especially on Linux. If a plugin can’t write, that’s usually why. Adjust the folder’s permissions or ownership to match.
  • Environment variables: A WordPress that can’t connect to the database almost always comes down to a mismatched credential between the two services. Check that the MYSQL_* and WORDPRESS_DB_* values line up.
  • Container logs: When a container won’t start, docker compose logs tells you why before you start guessing.

Conclusion

That’s the whole loop: one docker-compose.yml, one docker compose up -d, and you’ve got a WordPress site that matches what your teammates run and looks a lot more like production than a hand-rolled local stack ever will. You edit code on your machine, run WP-CLI inside the container, and tear the whole thing down without leaving a mess behind.

Start with this setup for your next project. Once it’s second nature, the same pieces carry you into custom images and real deployments whenever you’re ready for them.

Next: 7 Essential Productivity Tools for WordPress Users

Leave a Comment

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


Scroll to Top