用Docker打造最佳效能的Wordpress環境

要做的事:Docker → WordPress 可用流程

1. 建立 Docker 架構


2. 主機層 Proxy (Ubuntu Nginx)

proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port  443;

3. WordPress 部署

docker compose exec wp-cli wp core download --allow-root

4. 修正容器問題

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

5. Redis 整合

define( 'WP_REDIS_HOST', 'redis' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 1 );
docker compose exec wp-cli wp redis enable --allow-root
docker compose exec wp-cli wp redis status --allow-root

6. WordPress 網站成功啟動

📂 專案目錄結構

wordpress-perf/
├── docker-compose.yml
├── .env
├── nginx/
│   └── conf.d/
│       ├── wordpress.conf
│       └── 00-cache.conf
├── cron/
│   └── wp-cron.sh
└── README.md

⚙️ 檔案內容

1. .env

HTTP_PORT=8080

DB_NAME=wp
DB_USER=wpuser
DB_PASSWORD=change_me
DB_ROOT_PASSWORD=change_root

# PHP 記憶體/子程序調整(4C/4G RAM)
PHP_MEMORY_LIMIT=256M
PHP_MAX_CHILDREN=10
PHP_MAX_REQUESTS=400

2. docker-compose.yml

services:
  nginx:
    image: nginx:1.25-alpine
    restart: always
    ports:
      - "127.0.0.1:${HTTP_PORT:-8080}:80"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - wp_data:/var/www/html:ro
      - cache_data:/var/cache/nginx
    depends_on:
      - php

  php:
    build:
      context: .
      dockerfile_inline: |
        FROM wordpress:php8.3-fpm-alpine
        RUN docker-php-ext-install mysqli pdo pdo_mysql
        COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
    restart: always
    environment:
      WORDPRESS_DB_NAME: ${DB_NAME}
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_HOST: db:3306
      PHP_MEMORY_LIMIT: ${PHP_MEMORY_LIMIT}
    volumes:
      - wp_data:/var/www/html

  db:
    image: mariadb:10.11
    restart: always
    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

  redis:
    image: redis:7-alpine
    restart: always
    volumes:
      - redis_data:/data

  wp-cli:
    image: wordpress:cli-php8.3
    depends_on:
      - php
      - db
    volumes:
      - wp_data:/var/www/html
    entrypoint: wp

  cron:
    image: wordpress:cli-php8.3
    depends_on:
      - php
    volumes:
      - wp_data:/var/www/html
      - ./cron:/cron
    entrypoint: /cron/wp-cron.sh

volumes:
  wp_data:
  db_data:
  redis_data:
  cache_data:

4. nginx/conf.d/wordpress.conf

server {
  listen 80 default_server;
  server_name _;
  root /var/www/html;
  index index.php index.html;

  # 跳過快取條件
  set $skip_cache 0;
  if ($request_method = POST) { set $skip_cache 1; }
  if ($query_string != "")   { set $skip_cache 1; }
  if ($http_cookie ~* "wordpress_logged_in_|woocommerce_items_in_cart|woocommerce_cart_hash|wp_woocommerce_session_") { set $skip_cache 1; }
  if ($request_uri ~* "^/(wp-admin/|wp-login\.php|cart|checkout|my-account|wc-api/|wp-json/)") { set $skip_cache 1; }
  if ($request_uri ~* "add-to-cart=") { set $skip_cache 1; }
  if ($request_uri ~* "admin-ajax\.php") { set $skip_cache 1; }

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

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

    fastcgi_buffers 16 32k;
    fastcgi_buffer_size 32k;
    fastcgi_read_timeout 120s;

    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    fastcgi_cache PHP_MICRO;
    fastcgi_cache_valid 200 301 302 5s;

    add_header X-Cache $upstream_cache_status;
    fastcgi_param HTTPS on;
    fastcgi_param SERVER_PORT 443;
    fastcgi_param HTTP_X_FORWARDED_PROTO https;
  }

  location ~* \.(?:css|js|jpg|jpeg|gif|png|svg|webp|ico|ttf|otf|woff|woff2)$ {
    expires 30d;
    access_log off;
  }

  client_max_body_size 64m;
}

5. cron/wp-cron.sh

#!/bin/sh
set -e
# 每 1 分鐘跑一次 wp-cron
while true; do
  wp --path=/var/www/html --allow-root cron event run --due-now >/dev/null 2>&1 || true
  sleep 60
done

6. README.md(流程文件)

# WordPress on Docker (WooCommerce Ready)

## Services
- Nginx 1.25 (reverse proxy inside container)
- PHP-FPM 8.3 (with mysqli, pdo_mysql)
- MariaDB 10.11
- Redis 7 (object cache)
- WP-CLI
- Cron container for wp-cron

## Usage
```bash
docker compose up -d

WordPress setup

docker compose exec wp-cli wp core download --allow-root
docker compose exec wp-cli wp config create \
  --dbname=$DB_NAME --dbuser=$DB_USER --dbpass=$DB_PASSWORD \
  --dbhost=db:3306 --skip-check --allow-root
docker compose exec wp-cli wp core install \
  --url="https://mysite.com" \
  --title="MySite Shop" \
  --admin_user="admin" \
  --admin_password="ChangeMe123!" \
  --admin_email="you@example.com" \
  --allow-root

Redis setup

docker compose exec wp-cli wp config set WP_REDIS_HOST 'redis' --allow-root
docker compose exec wp-cli wp config set WP_REDIS_PORT 6379 --raw --allow-root
docker compose exec wp-cli wp config set WP_REDIS_DATABASE 1 --raw --allow-root
docker compose restart php
docker compose exec wp-cli wp redis enable --allow-root

Proxy setup (Host machine)

Nginx reverse proxy:

server {
    listen 443 ssl http2;
    server_name mysite.com;

    ssl_certificate     /etc/letsencrypt/live/mysite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Result


修訂版本 #2
由 tainan 建立於 2025-08-22 00:30:38 UTC
由 tainan 更新於 2025-08-22 01:08:26 UTC