BLOG POSTS
How to Install WordPress with Docker Compose

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.

Leave a reply

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