← Back to Home

WordPress Docker Production Deployment Pitfalls Complete Guide

DockerWordPressdeploymentcontainerizationNginx

Why Docker Instead of宝塔 or Lnmp

WordPress hosting in 2026 isn't just "install a panel" anymore. I used 宝塔, Lnmp, and manual compilation, and eventually switched to Docker for one reason: environment consistency.

When you have 3 servers and need to migrate WordPress on all of them, 宝塔's version differences will drive you crazy. With docker-compose up -d on one file, all 3 machines run identical environments.

But deploying WordPress on Docker has a unique set of pitfalls. This article covers 7 I actually hit.

My docker-compose.yml Configuration (Latest 2026)

Here's the complete configuration I tested working in 2026, including Nginx+PHP-FPM+MySQL+Redis:

version: '3.8'

services:
  nginx:
    image: nginx:1.25-alpine
    container_name: wp_nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./wordpress:/var/www/html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
    restart: unless-stopped

  php:
    image: php:8.3-fpm-alpine
    container_name: wp_php
    volumes:
      - ./wordpress:/var/www/html
    depends_on:
      - db
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_NAME=wordpress
      - WORDPRESS_DB_USER=wp_user
      - WORDPRESS_DB_PASSWORD=your_strong_password
    restart: unless-stopped

  db:
    image: mysql:8.0
    container_name: wp_mysql
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=wordpress
      - MYSQL_USER=wp_user
      - MYSQL_PASSWORD=your_strong_password
      - MYSQL_ROOT_PASSWORD=root_strong_password
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    container_name: wp_redis
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data
    restart: unless-stopped

volumes:
  db_data:
  redis_data:

Key Version Confirmations (May 2026):

Pitfall 1: UID 1000 Permission Problem—The Root Cause of Plugin Update Failures

Symptom: WordPress admin shows "Unable to write files," plugin updates fail, media upload errors.

Cause: Docker containers run as www-data (UID 33) or custom users, while host-mounted volumes belong to your user account (UID 1000). The UID mismatch on both sides causes permission failures.

Solution: Unify PHP container user UID in docker-compose.yml:

php:
  image: php:8.3-fpm-alpine
  user: "1000:1000"  # matches host user
  volumes:
    - ./wordpress:/var/www/html

But this creates a new problem—if the host runs containers as root, UID 1000 may not exist. A better approach uses PGID 1000:

php:
  image: php:8.3-fpm-alpine
  user: "1000:82"  # 1000=your user, 82=www-data group

**Verification method**: Run ls -ln wordpress/ on host to confirm file ownership, then check inside container:

docker exec -it wp_php sh -c "id"
# should display uid=1000 gid=82

Pitfall 2: Nginx Cannot Read WordPress Files—Volume Mount Path Problem

Symptom: Visiting the site shows "File not found," but container logs show PHP-FPM running normally.

**Cause**: Official WordPress image places files in /var/www/html, but your host directory is mounted to the wrong path.

Correct nginx configuration (must be written in nginx/default.conf):

server {
    listen 80;
    server_name yourdomain.com;
    root /var/www/html;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires max;
        log_not_found off;
    }
}

**Note**: The fastcgi_pass php:9000; uses php as the docker-compose service name, not localhost.

Pitfall 3: MySQL Data Persistence Failure—Common Volume Mount Error

Symptom: After restarting containers, database is empty, all WordPress content lost.

Cause: Not using Docker volume correctly, data was stored in container writable layer (deleted when container removed).

Correct configuration (already shown in docker-compose.yml above):

volumes:
  db_data:  # named volume, managed by Docker

# instead of:
# volumes:
#   - /var/lib/mysql  # host path, may have permission issues

Verify persistence is working:

docker volume ls | grep wp
# should see wp_db_data

docker inspect wp_mysql | grep -A5 Mounts
# should see Destination: /var/lib/mysql type: volume

Pitfall 4: WordPress Cannot Connect to Redis—Inter-Container Communication DNS Problem

Symptom: Installed Redis Object Cache plugin but connection fails, site is still slow.

**Cause**: When WordPress container connects to Redis, hostname should be redis (docker-compose service name), not localhost or 127.0.0.1.

Configure Redis in wp-config.php:

define('WP_REDIS_HOST', 'redis');
define('WP_REDIS_PORT', '6379');
define('WP_REDIS_TIMEOUT', '2.5');
define('WP_REDIS_READ_TIMEOUT', '2.5');
define('WP_REDIS_DATABASE', '0');

Verify Redis is reachable:

docker exec -it wp_php sh -c "nc -zv redis 6379"
# success output: redis (172.x.x.x:6379) open

Pitfall 5: 502 Bad Gateway After WordPress Upgrade—PHP-FPM Process Crash

Symptom: Upgrading theme or plugin in WordPress admin, site immediately shows 502 error.

Cause: PHP-FPM default process count configured too low, all processes crash during high concurrency or plugin execution timeout.

Adjust PHP-FPM configuration in docker-compose.yml:

php:
  image: php:8.3-fpm-alpine
  volumes:
    - ./wordpress:/var/www/html
    - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini:ro

php/local.ini configuration content:

memory_limit = 256M
max_execution_time = 300
upload_max_filesize = 64M
post_max_size = 64M

[www]
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500

Pitfall 6: HTTP Protocol Problem—Blank Page or Redirect Loop

Symptom: After visiting the site, redirects to HTTPS, or page is blank with no errors.

Cause: Nginx inside Docker doesn't know if external proxy/CDN is used, need to force correct protocol in wp-config.php.

Add to wp-config.php:

// Force HTTP_HOST correct
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] ?? 'yourdomain.com';

// If using reverse proxy/load balancer
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Nginx proxy_headers configuration (if external proxy exists):

proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Pitfall 7: Site Won't Open After docker-compose down—Network Cleanup Problem

Symptom: After executing docker-compose down then up, site inaccessible but all containers appear to be running normally.

Cause: Docker network got cleaned up but wasn't correctly rebuilt, containers can't resolve each other's hostnames.

Solution: Use docker-compose down --remove-orphans instead of plain down:

# Stop and clean (recommended)
docker-compose down --remove-orphans

# Full restart (completely solves network issues)
docker-compose down -v  # -v deletes volumes, use with caution!
docker-compose up -d

Daily maintenance commands:

# View all container status
docker-compose ps

# View logs
docker-compose logs -f nginx

# Restart single service
docker-compose restart php

# Full config reload
docker-compose down && docker-compose up -d

Summary: Core Principles for Deploying WordPress with Docker

1. UID matching: Host user UID and container user UID must match, otherwise all file operations encounter permission issues

2. Use named volumes: MySQL and Redis data must use Docker-managed named volumes, not host paths

3. Service name is hostname: Inter-container communication uses docker-compose service names (php, db, redis), not localhost

4. Configure PHP-FPM proactively: Default configuration is too low, WordPress plugins easily crash during execution

5. Network rebuild uses --remove-orphans: Avoid network disconnection after down/up

If it's your first time deploying WordPress on Docker, test the complete workflow on a local VM first, then migrate to production servers.

👉 Start now: https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books ⭐ MiniMax Token Plan
← Back to Home