Skip to main content

Course Progress

Loading...

Setting up WordPress with Docker

Duration: 60 minutes
Module 4: Session 5.2

Learning Objectives

  • Create a complete docker-compose.yml for WordPress
  • Configure WordPress, MySQL, and phpMyAdmin containers
  • Implement persistent volumes for data storage
  • Set up container networking and environment variables

Introduction

Docker Compose simplifies WordPress deployment by orchestrating multiple containers with a single configuration file. We'll build a complete WordPress development environment step by step.

💡
What We're Building
A complete WordPress stack with MySQL database, phpMyAdmin for database management, and persistent storage for all data.

Project Structure

First, let's create our project directory structure:

# Create project directory
mkdir wordpress-docker
cd wordpress-docker

# Create subdirectories
mkdir -p config/php
mkdir -p wp-content/themes
mkdir -p wp-content/plugins
mkdir -p wp-content/uploads
mkdir -p database/backup

# Create configuration files
touch docker-compose.yml
touch .env
touch .env.example
touch config/php/uploads.ini
graph TD A[wordpress-docker/] --> B[docker-compose.yml] A --> C[.env] A --> D[config/] D --> E[php/] E --> F[uploads.ini] A --> G[wp-content/] G --> H[themes/] G --> I[plugins/] G --> J[uploads/] A --> K[database/] K --> L[backup/]

Creating docker-compose.yml

Let's build our docker-compose.yml file step by step:

Step 1: Basic Structure and Version

# docker-compose.yml
version: '3.8'

services:
  # Our services will go here

volumes:
  # Named volumes for data persistence

networks:
  # Custom network for container communication

Step 2: WordPress Service Configuration

version: '3.8'

services:
  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wp-site
    restart: unless-stopped
    ports:
      - "${WP_PORT:-8080}:80"
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: ${DB_NAME:-wordpress}
      WORDPRESS_DB_USER: ${DB_USER:-wpuser}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-wppass}
      WORDPRESS_TABLE_PREFIX: ${WP_PREFIX:-wp_}
      WORDPRESS_DEBUG: ${WP_DEBUG:-false}
      WORDPRESS_DEBUG_LOG: ${WP_DEBUG_LOG:-false}
      WORDPRESS_DEBUG_DISPLAY: ${WP_DEBUG_DISPLAY:-false}
    volumes:
      - wordpress_data:/var/www/html
      - ./wp-content:/var/www/html/wp-content
      - ./config/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    depends_on:
      - mysql
    networks:
      - wp-network

Step 3: MySQL Database Configuration

mysql:
    image: mysql:8.0
    container_name: wp-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpass}
      MYSQL_DATABASE: ${DB_NAME:-wordpress}
      MYSQL_USER: ${DB_USER:-wpuser}
      MYSQL_PASSWORD: ${DB_PASSWORD:-wppass}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./database/backup:/backup
    ports:
      - "${DB_PORT:-3306}:3306"
    command: [
      '--default-authentication-plugin=mysql_native_password',
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_unicode_ci'
    ]
    networks:
      - wp-network

Step 4: phpMyAdmin Configuration

phpmyadmin:
    image: phpmyadmin:latest
    container_name: wp-phpmyadmin
    restart: unless-stopped
    ports:
      - "${PMA_PORT:-8081}:80"
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: ${DB_USER:-wpuser}
      PMA_PASSWORD: ${DB_PASSWORD:-wppass}
      UPLOAD_LIMIT: 300M
    depends_on:
      - mysql
    networks:
      - wp-network

Step 5: Volumes and Networks

volumes:
  wordpress_data:
    driver: local
  mysql_data:
    driver: local

networks:
  wp-network:
    driver: bridge

Complete docker-compose.yml

Here's the complete configuration file:

# docker-compose.yml
version: '3.8'

services:
  wordpress:
    image: wordpress:6.4-php8.2-apache
    container_name: wp-site
    restart: unless-stopped
    ports:
      - "${WP_PORT:-8080}:80"
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: ${DB_NAME:-wordpress}
      WORDPRESS_DB_USER: ${DB_USER:-wpuser}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-wppass}
      WORDPRESS_TABLE_PREFIX: ${WP_PREFIX:-wp_}
      WORDPRESS_DEBUG: ${WP_DEBUG:-false}
      WORDPRESS_DEBUG_LOG: ${WP_DEBUG_LOG:-false}
      WORDPRESS_DEBUG_DISPLAY: ${WP_DEBUG_DISPLAY:-false}
    volumes:
      - wordpress_data:/var/www/html
      - ./wp-content:/var/www/html/wp-content
      - ./config/php/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    depends_on:
      - mysql
    networks:
      - wp-network

  mysql:
    image: mysql:8.0
    container_name: wp-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpass}
      MYSQL_DATABASE: ${DB_NAME:-wordpress}
      MYSQL_USER: ${DB_USER:-wpuser}
      MYSQL_PASSWORD: ${DB_PASSWORD:-wppass}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./database/backup:/backup
    ports:
      - "${DB_PORT:-3306}:3306"
    command: [
      '--default-authentication-plugin=mysql_native_password',
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_unicode_ci'
    ]
    networks:
      - wp-network

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: wp-phpmyadmin
    restart: unless-stopped
    ports:
      - "${PMA_PORT:-8081}:80"
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: ${DB_USER:-wpuser}
      PMA_PASSWORD: ${DB_PASSWORD:-wppass}
      UPLOAD_LIMIT: 300M
    depends_on:
      - mysql
    networks:
      - wp-network

volumes:
  wordpress_data:
    driver: local
  mysql_data:
    driver: local

networks:
  wp-network:
    driver: bridge

Environment Variables (.env)

Create a.envfile to store sensitive configuration:

# .env
# WordPress Configuration
WP_PORT=8080
WP_PREFIX=wp_
WP_DEBUG=true
WP_DEBUG_LOG=true
WP_DEBUG_DISPLAY=false

# Database Configuration
DB_NAME=wordpress
DB_USER=wpuser
DB_PASSWORD=SecurePassword123!
DB_ROOT_PASSWORD=RootPassword456!
DB_PORT=3306

# phpMyAdmin Configuration
PMA_PORT=8081
⚠️
Security Notice
Never commit.envfiles to version control. Add it to.gitignoreand provide.env.exampleinstead.
# .env.example
# WordPress Configuration
WP_PORT=8080
WP_PREFIX=wp_
WP_DEBUG=false
WP_DEBUG_LOG=false
WP_DEBUG_DISPLAY=false

# Database Configuration
DB_NAME=wordpress
DB_USER=wpuser
DB_PASSWORD=ChangeThisPassword
DB_ROOT_PASSWORD=ChangeThisRootPassword
DB_PORT=3306

# phpMyAdmin Configuration
PMA_PORT=8081

PHP Configuration

Create custom PHP settings for WordPress:

# config/php/uploads.ini
; Maximum allowed size for uploaded files
upload_max_filesize = 64M

; Maximum size of POST data
post_max_size = 64M

; Maximum execution time
max_execution_time = 300

; Maximum input time
max_input_time = 300

; Memory limit
memory_limit = 256M

; Maximum input variables
max_input_vars = 3000

; File uploads
file_uploads = On

; Session configuration
session.gc_maxlifetime = 1440

Managing Persistent Volumes

Understanding volume management is crucial for data persistence:

graph LR subgraph "Named Volumes" V1[wordpress_data] V2[mysql_data] end subgraph "Bind Mounts" B1[./wp-content] B2[./database/backup] B3[./config/php] end subgraph "Containers" C1[WordPress] C2[MySQL] end V1 --> C1 V2 --> C2 B1 --> C1 B2 --> C2 B3 --> C1 style V1 fill:#e3f2fd style V2 fill:#e3f2fd style B1 fill:#e8f5e9 style B2 fill:#e8f5e9 style B3 fill:#e8f5e9

Volume Commands

# List all volumes
docker volume ls

# Inspect a volume
docker volume inspect wordpress-docker_wordpress_data

# Backup WordPress files
docker run --rm \
  -v wordpress-docker_wordpress_data:/data \
  -v $(pwd)/backup:/backup \
  alpine tar czf /backup/wordpress-backup.tar.gz -C /data .

# Backup MySQL database
docker exec wp-mysql mysqldump \
  -u root -pRootPassword456! \
  wordpress > ./database/backup/wordpress-backup.sql

# Remove unused volumes
docker volume prune

Best Practices for Docker WordPress Setup

  • Use specific image versions:Never uselatesttags in production
  • Separate data volumes:Keep WordPress files and database data in separate volumes
  • Network isolation:Use custom networks instead of the default bridge
  • Environment variables:Store all configuration in.envfiles
  • Regular backups:Implement automated backup strategies for volumes
  • Resource limits:Set memory and CPU limits in production

Real World Example: Multi-Site Setup

Setting up WordPress Multisite with Docker:

# docker-compose-multisite.yml
version: '3.8'

services:
  wordpress-multisite:
    image: wordpress:6.4-php8.2-apache
    container_name: wp-multisite
    restart: unless-stopped
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_NAME: multisite
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_CONFIG_EXTRA: |
        /* Multisite configuration */
        define('WP_ALLOW_MULTISITE', true);
        define('MULTISITE', true);
        define('SUBDOMAIN_INSTALL', false);
        define('DOMAIN_CURRENT_SITE', 'localhost');
        define('PATH_CURRENT_SITE', '/');
        define('SITE_ID_CURRENT_SITE', 1);
        define('BLOG_ID_CURRENT_SITE', 1);
    volumes:
      - multisite_data:/var/www/html
      - ./multisite-content:/var/www/html/wp-content
    depends_on:
      - mysql
    networks:
      - wp-multisite-network

  mysql:
    image: mysql:8.0
    container_name: wp-multisite-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: multisite
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - multisite_mysql:/var/lib/mysql
    networks:
      - wp-multisite-network

volumes:
  multisite_data:
  multisite_mysql:

networks:
  wp-multisite-network:
    driver: bridge

Practice Exercise

Let's get your WordPress Docker environment running:

💻
Try It Now
  1. Create the project directory structure as shown above
  2. Copy the completedocker-compose.ymlconfiguration
  3. Create your.envfile with secure passwords
  4. Create theuploads.iniconfiguration
  5. Start the stack:docker-compose up -d
  6. Access WordPress athttp://localhost:8080
  7. Access phpMyAdmin athttp://localhost:8081
  8. Complete the WordPress installation wizard

Troubleshooting Common Issues

Port Already in Use

# Check what's using port 8080
sudo lsof -i :8080

# Change port in .env file
WP_PORT=8082

Permission Issues

# Fix ownership for wp-content
docker exec wp-site chown -R www-data:www-data /var/www/html/wp-content

# Set correct permissions
docker exec wp-site chmod -R 755 /var/www/html/wp-content

Database Connection Failed

# Check if MySQL is running
docker-compose ps

# View MySQL logs
docker-compose logs mysql

# Test connection
docker exec -it wp-mysql mysql -u wpuser -p

Additional Resources