
How to Install WordPress with Docker Compose
Setting up WordPress with Docker Compose is like having your development environment packaged into neat, reproducible containers that eliminate the classic “it works on my machine” problem. Instead of wrestling with manual PHP configurations, database setups, and server tweaks, you can get a complete WordPress stack running with just a few commands. This approach gives you version control over your entire infrastructure, makes scaling dead simple, and lets you spin up identical environments whether you’re developing locally or deploying to production servers.
How Docker Compose Transforms WordPress Deployment
Docker Compose orchestrates multiple containers to create your WordPress environment. Think of it as a conductor managing an orchestra β you’ve got your WordPress container (the PHP application), MySQL or MariaDB container (your database), and potentially additional services like Redis for caching or phpMyAdmin for database management.
The magic happens in the docker-compose.yml
file, which defines all your services, their relationships, and configurations. When you run docker-compose up
, it creates isolated containers that can communicate with each other through Docker’s internal networking, while keeping your host system clean.
This containerized approach offers several advantages over traditional installations:
- Environment consistency across development, staging, and production
- Easy version management for both WordPress and database
- Simplified backup and migration processes
- Resource isolation preventing conflicts with other applications
- Horizontal scaling capabilities for high-traffic scenarios
Complete Docker Compose Setup Guide
Let’s build a production-ready WordPress environment step by step. First, create a project directory and navigate into it:
mkdir wordpress-docker
cd wordpress-docker
Create the main docker-compose.yml
file with this configuration:
version: '3.8'
services:
wordpress:
image: wordpress:latest
restart: unless-stopped
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: secure_password_here
WORDPRESS_DB_NAME: wordpress
WORDPRESS_TABLE_PREFIX: wp_
volumes:
- wordpress_data:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
depends_on:
- db
networks:
- wordpress_network
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: secure_password_here
MYSQL_ROOT_PASSWORD: root_password_here
volumes:
- db_data:/var/lib/mysql
networks:
- wordpress_network
phpmyadmin:
image: phpmyadmin:latest
restart: unless-stopped
ports:
- "8081:80"
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: root_password_here
depends_on:
- db
networks:
- wordpress_network
volumes:
wordpress_data:
db_data:
networks:
wordpress_network:
driver: bridge
Create a PHP configuration file for upload limits:
echo "file_uploads = On
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 600" > uploads.ini
Launch your WordPress environment:
docker-compose up -d
The -d
flag runs containers in detached mode, so they continue running in the background. Your WordPress site will be accessible at http://localhost:8080
and phpMyAdmin at http://localhost:8081
.
Production-Ready Configuration Examples
For production deployments, you’ll want enhanced security and performance. Here’s an advanced configuration that includes SSL termination, Redis caching, and proper environment variable management:
version: '3.8'
services:
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
- wordpress_data:/var/www/html
depends_on:
- wordpress
networks:
- wordpress_network
wordpress:
image: wordpress:php8.1-fpm
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: ${DB_NAME}
WORDPRESS_CONFIG_EXTRA: |
define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', 6379);
define('WP_CACHE', true);
volumes:
- wordpress_data:/var/www/html
- ./custom.ini:/usr/local/etc/php/conf.d/custom.ini
depends_on:
- db
- redis
networks:
- wordpress_network
db:
image: mariadb:10.8
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./my.cnf:/etc/mysql/conf.d/custom.cnf
networks:
- wordpress_network
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- wordpress_network
volumes:
wordpress_data:
db_data:
redis_data:
networks:
wordpress_network:
driver: bridge
Create a .env
file to manage sensitive credentials:
DB_NAME=wordpress_prod
DB_USER=wp_user
DB_PASSWORD=your_secure_database_password
DB_ROOT_PASSWORD=your_secure_root_password
Performance Comparison and Optimization
Here’s how Docker WordPress stacks up against traditional installations in terms of performance and resource usage:
Metric | Docker WordPress | Traditional LAMP | Managed WordPress |
---|---|---|---|
Initial Setup Time | 5-10 minutes | 30-60 minutes | 2-5 minutes |
Memory Overhead | ~200MB extra | Baseline | Varies |
Response Time (avg) | ~5ms overhead | Baseline | Optimized |
Scalability | Excellent | Manual | Provider-dependent |
Environment Consistency | Perfect | Manual setup | Limited control |
The slight performance overhead is usually negligible compared to the operational benefits. For high-traffic sites, you can optimize performance with these Docker-specific tweaks:
# Add to your docker-compose.yml WordPress service
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
ulimits:
nproc: 65535
nofile:
soft: 65535
hard: 65535
Real-World Use Cases and Applications
Docker Compose WordPress setups shine in several scenarios. Development teams love the ability to have identical environments across all machines β no more debugging environment-specific issues. One team I worked with reduced their onboarding time from two days to 30 minutes just by dockerizing their WordPress development stack.
For agencies managing multiple client sites, you can create template docker-compose files and spin up new projects instantly. Here’s a multi-site setup that lets you run several WordPress instances with shared services:
version: '3.8'
services:
client1_wp:
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: shared_db:3306
WORDPRESS_DB_NAME: client1_wp
WORDPRESS_DB_USER: client1_user
WORDPRESS_DB_PASSWORD: client1_pass
ports:
- "8080:80"
networks:
- shared_network
client2_wp:
image: wordpress:latest
environment:
WORDPRESS_DB_HOST: shared_db:3306
WORDPRESS_DB_NAME: client2_wp
WORDPRESS_DB_USER: client2_user
WORDPRESS_DB_PASSWORD: client2_pass
ports:
- "8081:80"
networks:
- shared_network
shared_db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secure_root_password
volumes:
- ./init-databases.sql:/docker-entrypoint-initdb.d/init.sql
- shared_db_data:/var/lib/mysql
networks:
- shared_network
volumes:
shared_db_data:
networks:
shared_network:
Staging environments become trivial β just clone your production docker-compose setup, change the ports and database names, and you’re running a perfect staging copy. For VPS deployments, this approach eliminates server configuration headaches completely.
Common Pitfalls and Troubleshooting
Even with Docker’s reliability, you’ll hit some common issues. The most frequent problem is database connection failures during startup. WordPress containers often start before MySQL is fully ready, causing connection errors. Fix this with proper health checks:
services:
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
wordpress:
depends_on:
db:
condition: service_healthy
File permission issues plague many setups, especially when mounting local directories. WordPress needs write access to upload files and install plugins. Set proper ownership:
# After starting containers
docker-compose exec wordpress chown -R www-data:www-data /var/www/html
docker-compose exec wordpress find /var/www/html -type d -exec chmod 755 {} \;
docker-compose exec wordpress find /var/www/html -type f -exec chmod 644 {} \;
Memory exhaustion hits when processing large uploads or running resource-intensive plugins. Monitor container resource usage:
docker stats
For persistent storage issues, remember that Docker volumes persist data between container restarts, but removing volumes destroys data permanently. Always backup volumes before major changes:
docker run --rm -v wordpress_data:/data -v $(pwd):/backup alpine tar czf /backup/wordpress-backup.tar.gz -C /data .
Best Practices and Security Considerations
Security in containerized WordPress requires attention to several layers. Never use default passwords in production β generate strong, unique credentials for all database users. Use Docker secrets for sensitive data in production environments:
version: '3.8'
services:
wordpress:
image: wordpress:latest
environment:
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Keep your images updated by regularly pulling the latest versions. WordPress security patches come frequently, and Docker makes updates painless:
docker-compose pull
docker-compose up -d
For production deployments on dedicated servers, implement proper logging and monitoring. Centralize logs with a logging driver:
services:
wordpress:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Network security matters too. Never expose database ports directly to the internet. Use Docker’s internal networking and only expose web-facing services. Consider implementing reverse proxy with automated SSL certificates using Let’s Encrypt.
The official Docker Compose documentation provides comprehensive reference material for advanced configurations. For WordPress-specific containerization best practices, the WordPress Docker Hub page offers detailed environment variable documentation and usage examples.
Regular backups remain crucial even with containerized setups. Automate database dumps and volume backups with cron jobs or orchestration tools. Docker Compose gives you the infrastructure reliability, but data protection strategies are still your responsibility.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.