WordPress Development with Docker: A Beginner’s Step-by-Step Guide
If you’ve faced issues like “it works on my machine” or struggled with dependencies while developing WordPress, this guide is for you. We’ll explore how Docker simplifies the WordPress development process, enabling you to create a consistent, reproducible local environment. This beginner’s guide will take you step-by-step through setting up Docker and Docker Compose to run WordPress alongside a database. Expect practical insights on managing themes and plugins, handling data, and eventually preparing for production.
1. Introduction — Why use Docker for WordPress development?
Docker can resolve common development hurdles such as environment inconsistencies or lengthy onboarding times. With this guide, you’ll learn to set up a local WordPress development environment using Docker and Docker Compose, specifically WordPress with MariaDB.
Quick overview of Docker and Docker Compose
- Docker creates lightweight, isolated containers that share the host kernel.
- Docker Compose allows you to define a multi-container application in a single YAML file (e.g., WordPress + database + optional services).
Benefits of using Docker for WordPress
- Consistency: Everyone works with the same stack and versions.
- Isolation: No global PHP/MySQL versions to manage.
- Portability: Your project can be easily transferred between machines or CI.
- Faster onboarding: Simply run
docker-compose upto bootstrap everything.
Note: This guide is focused on local development. For production deployments, additional security measures such as SSL, secrets management, and scalable storage will be discussed later.
2. Prerequisites — What you need before getting started
Required tools
- Docker Desktop for macOS/Windows or Docker Engine + Docker Compose on Linux. Installation details can be found in the official Docker documentation.
- WP-CLI for command-line management of WordPress (optional but recommended): WP-CLI.
- A code editor such as Visual Studio Code.
Windows-specific tips
- If using Windows, install Docker Desktop and enable WSL2 for optimal performance. Refer to our WSL2 setup for Docker on Windows guide.
- For Windows containers, check out the Docker on Windows / Windows containers guide.
Basic knowledge assumed
- Familiarity with editing files, running commands in terminal/PowerShell, and basic Git operations.
Minimum machine requirements
- 4 GB RAM minimum; 8 GB+ recommended for comfortable multitasking.
- An SSD is recommended for improved file access speeds.
3. Quick architecture overview — What components make up the Docker WordPress stack
Typical containers
- WordPress: Runs the PHP application.
- Database: MariaDB or MySQL in a separate container.
- Optional services: phpMyAdmin for database management, Redis for caching, or Elasticsearch for better search capabilities.
Volumes and persistent data
- Ensure that database data and uploads persist outside the container lifecycles using Docker volumes or bind mounts. For development, you’ll often bind-mount
wp-contentfor immediate visibility of changes.
Networking between containers
- Docker Compose creates a network where services can communicate using service names (e.g.,
db). Refer to this container networking basics primer for more information.
4. Build the project — Create a simple Docker Compose setup
Create the project folder structure
my-wp-project/
├─ docker-compose.yml
├─ wp-content/ # your theme/plugin code (bind-mounted)
└─ .env # environment variables (gitignored)
Example docker-compose.yml
Below is a commented example for your docker-compose.yml.
version: '3.8'
services:
db:
image: mariadb:10.6
restart: always
environment:
MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
MYSQL_DATABASE: "${DB_NAME}"
MYSQL_USER: "${DB_USER}"
MYSQL_PASSWORD: "${DB_PASSWORD}"
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:6.4-php8.1-apache
depends_on:
- db
ports:
- "8000:80" # Visit http://localhost:8000
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: "${DB_USER}"
WORDPRESS_DB_PASSWORD: "${DB_PASSWORD}"
WORDPRESS_DB_NAME: "${DB_NAME}"
volumes:
- ./wp-content:/var/www/html/wp-content
restart: always
volumes:
db_data:
Key fields explained
- image: Use pinned tags (e.g.,
wordpress:6.4-php8.1-apache) for reproducibility. - ports: Maps host port to container port (8000 on host -> 80 in container).
- volumes: Bind mount
./wp-contentfor development, whiledb_dataensures persistence for the database. - environment: Configuration variables for WordPress.
- depends_on: Ensures the start order but does not guarantee the database is ready; health checks or wait scripts may be needed.
Start the stack
To start your containers:
# start in foreground
docker-compose up
# or in detached mode
docker-compose up -d
On the first run, Docker will pull images, create volumes, and initialize WordPress. Access it at http://localhost:8000 to complete the WordPress setup.
Stopping and removing containers
To stop and remove your containers:
# stop containers
docker-compose down
# remove containers and named volumes
docker-compose down --volumes
Note: --volumes will delete the database data stored in named volumes.
5. Development workflow — Editing code, themes, and plugins
Live edits with bind-mounting
Using ./wp-content:/var/www/html/wp-content allows for immediate viewing of changes in your browser without needing to rebuild images.
| Aspect | Bind mount (./wp-content) | Named volume (docker volume) |
|---|---|---|
| Immediate live edits | ✅ | ❌ (requires copy or rebuild) |
| Suitable for development | ✅ | ⚠️ mainly for data/persistence |
| Performance | ⚠️ can be slow on macOS/Windows | ✅ better performance |
| Ease of backups | Easy (standard file tools) | Requires Docker commands |
Using an IDE and debugging
Your IDE can be used to edit files. For step-through debugging, enable Xdebug in your PHP image or use a separate PHP-FPM container with Xdebug configured.
WP-CLI inside containers
WP-CLI is accessible within the WordPress container. Some commands include:
# Install a plugin
docker-compose exec wordpress wp plugin install query-monitor --activate
# Export the database
docker-compose exec wordpress wp db export /var/www/html/wp-content/db-dump.sql
# Safe search-replace operation
docker-compose exec wordpress wp search-replace 'http://localhost:8000' 'https://example.com' --all-tables
Version control tips
Track your theme/plugin source code, composer.json, package.json for builds. Add .env, and db_data (local DB dumps should be ignored) to .gitignore. Avoid committing node_modules or vendor binaries to maintain an efficient workflow.
Performance on macOS/Windows
If you experience slow performance with bind mounts, consider using docker-sync or install WSL2 on Windows (WSL2 setup guide).
6. Data management — Backups, imports, and migrations
Exporting/importing the database
Use WP-CLI or mysqldump. WP-CLI excels at managing serialized data during search/replace operations:
# Export using WP-CLI
docker-compose exec wordpress wp db export -
# or export to file in the container
docker-compose exec wordpress wp db export /var/www/html/wp-content/db-dump.sql
# Alternatively, use mysqldump from the host
docker-compose exec db sh -c 'exec mysqldump --databases "$DB_NAME" -u$DB_USER -p"$DB_PASSWORD"' > db-dump.sql
Backing up uploads and wp-content
For bind-mounted wp-content, simply copy the local folder. For named volumes, use a temporary container:
docker run --rm -v myproject_db_data:/from -v $(pwd)/backup:/to alpine sh -c "cd /from && tar czf /to/db-data.tgz ."
Migrating from local Docker to production
Dump the database, transfer wp-content/uploads, and run a wp search-replace command to swap URLs. Here’s a safe replacement example:
docker-compose exec wordpress wp search-replace 'http://localhost:8000' 'https://my-production-site.com' --all-tables --skip-columns=guid
7. Security & configuration best practices for dev and production
Keep secrets out of source control
Sensitive values should be stored in an .env file and listed in .gitignore. Reference them in docker-compose.yml with ${VAR}.
File permissions and ownership
When using bind mounts, ensure file ownership matches container UID/GID. Adjust permissions as necessary:
docker-compose exec wordpress chown -R www-data:www-data wp-content
Development vs production differences
| Concern | Development | Production |
|---|---|---|
| Exposed services | Often exposed (phpMyAdmin) | Minimize exposure (no public phpMyAdmin) |
| Debugging | WP_DEBUG enabled | WP_DEBUG disabled, regulated logging |
| Source code | Allow bind mounts | Copy into images, no mounts |
| Secrets | Use .env and local files | Implement secrets manager (e.g., Vault) |
Basic production hardening
- Avoid exposing tools like phpMyAdmin publicly.
- Use strong database passwords and perform periodic credential rotations.
- Serve your site over HTTPS with a reverse proxy (Traefik/NGINX) and enable automatic Let’s Encrypt certificates. Pin image versions and build tailored Docker images with only necessary extensions for production deployments.
8. Common issues and troubleshooting
Useful commands
docker-compose ps
docker-compose logs -f wordpress
docker-compose exec wordpress bash
docker volume ls
docker volume inspect myproject_db_data
Database connection errors
Common root causes include wrong DB host configurations (should be db), incorrect credentials, or the database not being ready during WordPress initialization. Implement health checks for the database service or employ a simple wait-for script to retry connections.
Permission errors with uploads
If uploads fail, check the ownership of wp-content/uploads and ensure it’s assigned to the webserver user (www-data for Debian/Ubuntu images).
Slow performance on macOS/Windows
For optimal performance, consider using WSL2 on Windows or eliminate bind mounts for high I/O operations. Tools like docker-sync can help alleviate these issues.
Inspect logs for clues
Use docker-compose logs -f wordpress and docker-compose logs -f db to check container logs for errors.
9. Next steps — Testing, CI, and deploying a containerized WordPress
Automated testing and CI
Set up your Docker Compose stack in CI environments (GitHub Actions, GitLab CI), run PHPUnit or WP-CLI tests, and clear the environment afterward. Example CI steps might include using services in GitHub Actions or executing docker-compose up -d in a job, followed by tests and cleanup with docker-compose down --volumes.
Building a production image
Utilize a multi-stage Dockerfile to build assets (npm/webpack) and create a streamlined PHP image for production purposes. Enhance performance by enabling opcache and disabling Xdebug, while limiting installed PHP extensions to necessary ones.
Deployment patterns
- For small sites, a single-server Compose setup is sufficient.
- For scaling and resilience, consider using Kubernetes or managed platforms like Cloud Run or Fargate. In front, apply a reverse proxy like Traefik or NGINX for SSL termination and routing.
Refer to our deployment strategies and Windows automation articles for detailed guidance: Windows deployment strategies and Windows automation tips.
10. Resources & further reading
Authoritative docs and tutorials referenced
Cheat sheet of common commands
# Start
docker-compose up -d
# View logs
docker-compose logs -f
# Execute WP-CLI
docker-compose exec wordpress wp plugin install akismet --activate
# Stop and remove containers
docker-compose down
# Remove containers and volumes
docker-compose down --volumes
Recommended next steps
- Clone an example repository and run
docker-compose up -dto see the stack in action. - Create a theme folder in
wp-content/themes/your-themeand begin editing. - Use WP-CLI commands to automate routine tasks and migrations.
Further reading
Thanks for reading! Docker empowers you to create isolated WordPress environments within minutes. Explore, build your workflow, and apply the production hardening tips outlined in this guide when you’re ready to go live.