T-CREATOR

WordPress を Docker で最速構築:開発/本番の環境差分をなくす手順

WordPress を Docker で最速構築:開発/本番の環境差分をなくす手順

WordPress のローカル開発環境を本格的に構築しようとした際、「開発環境では動くのに本番環境で動かない」という経験はありませんか。この問題の根本的な解決策が Docker による環境統一です。

Docker を活用することで、開発から本番まで完全に同一の環境で WordPress を動かすことができます。今回は、実際のコードとともに、最短ルートで WordPress 環境を Docker 化する手順をご紹介します。環境差分によるトラブルを根絶し、効率的な開発ワークフローを手に入れましょう。

背景

従来の WordPress 環境構築の課題

従来の WordPress 環境構築では、多くの開発者が同じような課題に直面してきました。

まず、開発者それぞれのローカル環境が異なることが大きな問題となります。PHP のバージョン、Apache/Nginx の設定、MySQL のバージョンなど、微細な違いが予期しないエラーを引き起こします。

javascript// 開発環境: PHP 8.1
if (version_compare(PHP_VERSION, '8.1.0', '>=')) {
    // 新しい構文が使える
    $result = match($status) {
        'active' => 'アクティブ',
        'inactive' => '非アクティブ',
        default => '不明'
    };
}

上記のようなコードが開発環境では正常に動作しても、本番環境が PHP 7.4 だった場合、構文エラーが発生してしまいます。

さらに、チーム開発においては「私の環境では動く」問題が頻発します。新しいメンバーが参加するたびに、環境構築に時間を取られ、プロジェクトの進行に影響を与えてしまいます。

WordPress 特有の課題として、プラグインやテーマの依存関係も複雑になりがちです。開発環境と本番環境でプラグインのバージョンが異なると、予期しない動作が発生する可能性があります。

yaml# 従来の課題例
開発環境:
  - PHP: 8.1
  - MySQL: 8.0
  - WordPress: 6.3
  - プラグインA: 2.1.0

本番環境:
  - PHP: 7.4  バージョン違い
  - MySQL: 5.7  バージョン違い
  - WordPress: 6.2  バージョン違い
  - プラグインA: 2.0.5  バージョン違い

Docker による解決アプローチ

Docker は、これらの課題を根本的に解決する強力なソリューションです。コンテナ技術により、アプリケーションとその実行環境を丸ごとパッケージ化できます。

Docker の最大の利点は「コンテナとして動作する環境の完全な再現性」です。開発者のローカル環境、ステージング環境、本番環境すべてで、全く同じコンテナイメージを使用できます。

mermaidflowchart LR
    dev[開発環境] -->|同一イメージ| container[Docker コンテナ]
    staging[ステージング環境] -->|同一イメージ| container
    prod[本番環境] -->|同一イメージ| container
    container --> wp[WordPress アプリ]
    container --> php[PHP 8.1]
    container --> apache[Apache 2.4]

上図のように、すべての環境で同一の Docker イメージを使用することで、環境差分を完全になくすことができます。

Docker Compose を使用することで、WordPress 本体だけでなく、MySQL、Redis、Nginx など複数のサービスを組み合わせた環境も簡単に管理できます。

yaml# Docker Compose による統一環境
services:
  wordpress:
    image: wordpress:6.3-php8.1-apache
  mysql:
    image: mysql:8.0
  redis:
    image: redis:7.0

さらに、バージョン管理システムとの連携により、環境設定もコードとして管理できるようになります。これにより、環境の変更履歴や、特定の時点での環境復元も可能となります。

課題

開発と本番の環境差分問題

開発と本番の環境差分は、WordPress 開発において最も深刻な問題の一つです。具体的にどのような問題が発生するのかを詳しく見てみましょう。

PHP バージョンの違いによる問題

開発環境で PHP 8.1 を使用していて、本番環境が PHP 7.4 の場合、以下のような問題が発生します。

php// PHP 8.1 で追加された Named Arguments
function create_post_meta($post_id, $meta_key, $meta_value, $unique = false) {
    return add_post_meta(
        post_id: $post_id,
        meta_key: $meta_key,
        meta_value: $meta_value,
        unique: $unique
    );
}

上記のコードは PHP 8.1 では正常に動作しますが、PHP 7.4 では構文エラーとなります。

データベースの違いによる問題

MySQL のバージョン違いにより、以下のような SQL の動作が変わることがあります。

sql-- MySQL 8.0 以降では動作するが、5.7 では異なる結果になる可能性
SELECT JSON_EXTRACT(meta_value, '$.price') as price
FROM wp_postmeta
WHERE meta_key = 'product_data'
ORDER BY price DESC;

WordPress 設定の差分

php// wp-config.php の設定が環境ごとに異なる例
define('WP_DEBUG', true);          // 開発環境
define('WP_DEBUG', false);         // 本番環境

define('WP_MEMORY_LIMIT', '256M'); // 開発環境
define('WP_MEMORY_LIMIT', '512M'); // 本番環境(より大きい)

これらの設定差分により、開発時には発見できなかった問題が本番環境で発生することがあります。

mermaidflowchart TD
    dev_issue[開発環境での問題] --> hidden[見つからない問題]
    hidden --> prod_deploy[本番デプロイ]
    prod_deploy --> prod_error[本番エラー発生]
    prod_error --> emergency[緊急対応]
    emergency --> downtime[サービス停止]

    style prod_error fill:#ff6b6b
    style emergency fill:#ff6b6b
    style downtime fill:#ff6b6b

上図が示すように、環境差分による問題は最終的にサービス停止という深刻な事態を招く可能性があります。

従来手法の限界

従来の環境構築手法には、根本的な限界があります。

手動セットアップの限界

各開発者が手動で環境をセットアップする場合、以下の問題が発生します。

bash# 開発者Aの環境構築手順
brew install php@8.1
brew install mysql@8.0
brew install composer

# 開発者Bの環境構築手順(微妙に異なる)
sudo apt-get install php8.1
sudo apt-get install mysql-server-8.0
curl -sS https://getcomposer.org/installer | php

同じ目的でも、OS やパッケージマネージャーの違いにより、微妙に異なる環境が構築されてしまいます。

XAMPP/MAMP の限界

XAMPP や MAMP といったパッケージソリューションも、以下の制約があります。

項目XAMPP/MAMP本番環境問題
OSWindows/macOSLinux異なる OS
PHP 設定開発用設定本番用設定セキュリティ設定の差分
拡張モジュール標準セットカスタム構成必要な拡張が不足
データベース設定緩い設定厳格な設定文字コードや照合順序の違い

Vagrant の課題

Vagrant による仮想環境も一定の効果はありますが、以下の課題があります。

ruby# Vagrantfile の例
Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y apache2 php mysql-server
    # 長い初期化スクリプトが必要
  SHELL
end

Vagrant は仮想マシン全体を起動するため、リソース消費が大きく、起動時間も長くなりがちです。また、仮想マシンの管理も複雑になります。

これらの従来手法の限界を克服するため、Docker による解決策が注目されています。

解決策

Docker Compose による環境統一

Docker Compose を使用することで、複数のサービスを組み合わせた WordPress 環境を簡単に管理できます。最も重要なのは、開発・本番すべての環境で同一の構成を使用することです。

まず、基本的なディレクトリ構造を確認しましょう。

textwordpress-docker/
├── docker-compose.yml
├── docker-compose.override.yml  # 開発環境用オーバーライド
├── docker-compose.prod.yml      # 本番環境用設定
├── Dockerfile
├── .env.example
├── .env
└── wordpress/
    ├── wp-content/
    │   ├── themes/
    │   └── plugins/
    └── wp-config.php

基本となる docker-compose.yml を作成します。この設定は開発・本番共通で使用する基盤となります。

yaml# docker-compose.yml - 基本設定
version: '3.8'

services:
  wordpress:
    build: .
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: mysql
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: ${DB_NAME}
    volumes:
      - ./wordpress:/var/www/html
    depends_on:
      - mysql

  mysql:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

環境変数は .env ファイルで管理し、機密情報をコードから分離します。

bash# .env ファイル
DB_NAME=wordpress
DB_USER=wp_user
DB_PASSWORD=secure_password_here
DB_ROOT_PASSWORD=root_password_here
WORDPRESS_TABLE_PREFIX=wp_

図で表すと、以下のような構成になります。

mermaidflowchart TB
    compose[Docker Compose] --> wp_container[WordPress コンテナ]
    compose --> mysql_container[MySQL コンテナ]

    wp_container --> wp_volume[WordPress ボリューム]
    mysql_container --> mysql_volume[MySQL データボリューム]

    env_file[.env ファイル] --> compose

    subgraph "共通基盤"
        compose
        env_file
    end

    subgraph "コンテナ群"
        wp_container
        mysql_container
    end

この構成により、開発者全員が全く同じ WordPress 環境を瞬時に起動できるようになります。

マルチステージビルドの活用

Docker のマルチステージビルドを活用することで、効率的で軽量なイメージを作成できます。開発時には開発用のツールを含み、本番時には不要なファイルを除外した最適化されたイメージを作成します。

dockerfile# Dockerfile - マルチステージビルド
# ステージ1: 開発用ベース
FROM wordpress:6.3-php8.1-apache as development

# 開発用パッケージのインストール
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    vim \
    wget \
    && rm -rf /var/lib/apt/lists/*

# Composer のインストール
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# 開発用 PHP 設定
COPY php.ini-development /usr/local/etc/php/php.ini

# Xdebug のインストール(開発環境のみ)
RUN pecl install xdebug && docker-php-ext-enable xdebug

本番用のステージを定義します。

dockerfile# ステージ2: 本番用イメージ
FROM wordpress:6.3-php8.1-apache as production

# 必要最小限のパッケージのみインストール
RUN apt-get update && apt-get install -y \
    && rm -rf /var/lib/apt/lists/*

# 本番用 PHP 設定
COPY php.ini-production /usr/local/etc/php/php.ini

# セキュリティ強化
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 755 /var/www/html

# ヘルスチェック用エンドポイント
COPY healthcheck.php /var/www/html/
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
    CMD curl -f http://localhost/healthcheck.php || exit 1

開発時と本番時でビルドターゲットを切り替えます。

yaml# docker-compose.override.yml - 開発環境用
version: '3.8'

services:
  wordpress:
    build:
      context: .
      target: development # 開発用ステージを使用
    ports:
      - '8080:80'
    environment:
      - XDEBUG_MODE=develop,debug
      - XDEBUG_CONFIG=client_host=host.docker.internal
    volumes:
      - ./wordpress:/var/www/html
      - ./logs:/var/log/apache2
yaml# docker-compose.prod.yml - 本番環境用
version: '3.8'

services:
  wordpress:
    build:
      context: .
      target: production # 本番用ステージを使用
    environment:
      - WORDPRESS_CONFIG_EXTRA=define('WP_DEBUG', false);
    volumes:
      - wordpress_data:/var/www/html
      - ./uploads:/var/www/html/wp-content/uploads

マルチステージビルドの効果を図で表すと以下のようになります。

mermaidflowchart LR
    dockerfile[Dockerfile] --> dev_stage[開発ステージ]
    dockerfile --> prod_stage[本番ステージ]

    dev_stage --> dev_image[開発用イメージ<br/>・Xdebug<br/>・Git<br/>・Composer<br/>・開発ツール]

    prod_stage --> prod_image[本番用イメージ<br/>・最小構成<br/>・セキュリティ強化<br/>・パフォーマンス最適化]

    dev_image --> dev_env[開発環境]
    prod_image --> prod_env[本番環境]

    style dev_image fill:#a8e6cf
    style prod_image fill:#ffd93d

このアプローチにより、開発時の利便性と本番時の効率性を両立できます。

環境変数による設定管理

環境変数を活用した設定管理により、同一のコードで異なる環境設定を実現できます。これは WordPress の設定ファイルにも適用できます。

まず、環境別の設定ファイルを準備します。

bash# .env.development - 開発環境用
WORDPRESS_ENV=development
WORDPRESS_DEBUG=true
WORDPRESS_DEBUG_LOG=true
WORDPRESS_DEBUG_DISPLAY=true
WP_MEMORY_LIMIT=256M
DB_HOST=mysql
REDIS_HOST=redis
SITE_URL=http://localhost:8080
ADMIN_EMAIL=dev@example.com
bash# .env.production - 本番環境用
WORDPRESS_ENV=production
WORDPRESS_DEBUG=false
WORDPRESS_DEBUG_LOG=false
WORDPRESS_DEBUG_DISPLAY=false
WP_MEMORY_LIMIT=512M
DB_HOST=mysql
REDIS_HOST=redis
SITE_URL=https://example.com
ADMIN_EMAIL=admin@example.com

これらの環境変数を読み込む wp-config.php を作成します。

php<?php
// wp-config.php - 環境変数を活用した設定
// 環境変数の読み込み
$wordpress_env = getenv('WORDPRESS_ENV') ?: 'development';

// データベース設定(環境変数から取得)
define('DB_NAME', getenv('DB_NAME'));
define('DB_USER', getenv('DB_USER'));
define('DB_PASSWORD', getenv('DB_PASSWORD'));
define('DB_HOST', getenv('DB_HOST'));
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');

// デバッグ設定(環境に応じて切り替え)
define('WP_DEBUG', filter_var(getenv('WORDPRESS_DEBUG'), FILTER_VALIDATE_BOOLEAN));
define('WP_DEBUG_LOG', filter_var(getenv('WORDPRESS_DEBUG_LOG'), FILTER_VALIDATE_BOOLEAN));
define('WP_DEBUG_DISPLAY', filter_var(getenv('WORDPRESS_DEBUG_DISPLAY'), FILTER_VALIDATE_BOOLEAN));

Redis キャッシュの設定も環境変数で管理します。

php// Redis 設定
if (getenv('REDIS_HOST')) {
    define('WP_REDIS_HOST', getenv('REDIS_HOST'));
    define('WP_REDIS_PORT', getenv('REDIS_PORT') ?: 6379);
    define('WP_REDIS_DATABASE', getenv('REDIS_DATABASE') ?: 0);
}

// メモリ制限の設定
define('WP_MEMORY_LIMIT', getenv('WP_MEMORY_LIMIT') ?: '256M');

// サイトURL の設定
define('WP_HOME', getenv('SITE_URL'));
define('WP_SITEURL', getenv('SITE_URL'));

セキュリティキーも環境変数で管理することで、より安全な運用が可能になります。

php// セキュリティキー(環境変数または自動生成)
$security_keys = [
    'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', 'NONCE_KEY',
    'AUTH_SALT', 'SECURE_AUTH_SALT', 'LOGGED_IN_SALT', 'NONCE_SALT'
];

foreach ($security_keys as $key) {
    $value = getenv("WORDPRESS_{$key}");
    if (!$value) {
        // 環境変数が設定されていない場合は自動生成
        $value = wp_generate_password(64, true, true);
    }
    define($key, $value);
}

具体例

基本的な Docker 構成

実際に動作する WordPress 環境を Docker で構築してみましょう。まず、プロジェクトディレクトリを作成し、必要なファイルを配置します。

bash# プロジェクトディレクトリの作成
mkdir wordpress-docker-project
cd wordpress-docker-project

# 必要なディレクトリ構造を作成
mkdir -p wordpress/wp-content/{themes,plugins,uploads}
mkdir -p mysql/data
mkdir -p logs

基本的な Dockerfile を作成します。この例では、公式 WordPress イメージをベースに、必要な拡張機能を追加しています。

dockerfile# Dockerfile
FROM wordpress:6.3-php8.1-apache

# 必要なPHP拡張機能をインストール
RUN docker-php-ext-install mysqli pdo pdo_mysql

# ImageMagick のインストール
RUN apt-get update && apt-get install -y \
    libmagickwand-dev \
    && pecl install imagick \
    && docker-php-ext-enable imagick \
    && rm -rf /var/lib/apt/lists/*

# Redis 拡張機能のインストール
RUN pecl install redis && docker-php-ext-enable redis

# カスタム PHP 設定をコピー
COPY ./config/php.ini /usr/local/etc/php/conf.d/custom.ini

PHP の設定ファイルを作成します。

ini; config/php.ini
; メモリ制限
memory_limit = 256M

; ファイルアップロード設定
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300

; エラー設定
log_errors = On
error_log = /var/log/php_errors.log

; セッション設定
session.cookie_secure = On
session.cookie_httponly = On
session.use_strict_mode = On

基本的な Docker Compose 設定を作成します。

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

services:
  wordpress:
    build: .
    container_name: wp_app
    restart: unless-stopped
    ports:
      - '8080:80'
    environment:
      WORDPRESS_DB_HOST: mysql:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress_password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wordpress:/var/www/html
      - ./logs:/var/log
    depends_on:
      mysql:
        condition: service_healthy
    networks:
      - wordpress_network

  mysql:
    image: mysql:8.0
    container_name: wp_mysql
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_password
      MYSQL_ROOT_PASSWORD: root_password
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      timeout: 20s
      retries: 10
    networks:
      - wordpress_network

volumes:
  mysql_data:

networks:
  wordpress_network:
    driver: bridge

開発環境用 docker-compose.yml

開発環境では、開発者の利便性を重視した設定を行います。デバッグ機能やログ出力を有効にし、ファイルの変更をリアルタイムで反映できるようにします。

yaml# docker-compose.override.yml (開発環境用オーバーライド)
version: '3.8'

services:
  wordpress:
    environment:
      # デバッグモードを有効化
      WORDPRESS_DEBUG: 1
      WORDPRESS_DEBUG_LOG: 1
      WORDPRESS_DEBUG_DISPLAY: 1
      # 開発用メール設定
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_DEBUG', true);
        define('WP_DEBUG_LOG', true);
        define('WP_DEBUG_DISPLAY', true);
        define('SCRIPT_DEBUG', true);
        define('SAVEQUERIES', true);

        // メール送信をログファイルに出力(開発環境用)
        define('WP_MAIL_LOGGING', true);
    volumes:
      # 開発時のライブリロード用
      - ./wordpress:/var/www/html
      - ./themes:/var/www/html/wp-content/themes
      - ./plugins:/var/www/html/wp-content/plugins
      - ./config/php-dev.ini:/usr/local/etc/php/conf.d/dev.ini
    ports:
      - '8080:80'

  # 開発用のメールキャッチャー
  mailhog:
    image: mailhog/mailhog:latest
    container_name: wp_mailhog
    ports:
      - '1025:1025' # SMTP
      - '8025:8025' # Web UI
    networks:
      - wordpress_network

  # Redis キャッシュ(開発環境用)
  redis:
    image: redis:7.0-alpine
    container_name: wp_redis
    ports:
      - '6379:6379'
    volumes:
      - redis_data:/data
    networks:
      - wordpress_network

  # phpMyAdmin(開発環境用)
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: wp_phpmyadmin
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: wordpress
      PMA_PASSWORD: wordpress_password
    ports:
      - '8081:80'
    depends_on:
      - mysql
    networks:
      - wordpress_network

volumes:
  redis_data:

開発環境用の PHP 設定ファイルも作成します。

ini; config/php-dev.ini - 開発環境用
; デバッグ設定
display_errors = On
display_startup_errors = On
error_reporting = E_ALL

; Xdebug 設定(PHP 8.1用)
zend_extension=xdebug
xdebug.mode=develop,debug,coverage
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.start_with_request=yes
xdebug.log=/var/log/xdebug.log

; 開発用のメモリ設定
memory_limit = 512M
max_execution_time = 0

開発環境の起動は以下のコマンドで行います。

bash# 開発環境の起動
docker-compose up -d

# ログの確認
docker-compose logs -f wordpress

# 特定のサービスのみ再起動
docker-compose restart wordpress

図で開発環境の構成を表すと以下のようになります。

mermaidflowchart TB
    dev[開発者] --> browser[ブラウザ :8080]
    dev --> phpmyadmin[phpMyAdmin :8081]
    dev --> mailhog[MailHog :8025]

    browser --> wp[WordPress コンテナ]
    wp --> mysql[MySQL コンテナ]
    wp --> redis[Redis コンテナ]
    wp --> mailhog_smtp[MailHog SMTP :1025]

    phpmyadmin --> mysql

    subgraph "開発者ツール"
        phpmyadmin
        mailhog
    end

    subgraph "WordPress アプリケーション"
        wp
        mysql
        redis
    end

本番環境用 docker-compose.yml

本番環境では、セキュリティ、パフォーマンス、監視機能を重視した設定を行います。

yaml# docker-compose.prod.yml - 本番環境用
version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: wp_nginx
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./ssl:/etc/nginx/ssl
      - wordpress_static:/var/www/html/wp-content
    depends_on:
      - wordpress
    networks:
      - wordpress_network

  wordpress:
    build:
      context: .
      target: production
    container_name: wp_app_prod
    restart: unless-stopped
    environment:
      # 本番環境用設定
      WORDPRESS_DEBUG: 0
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_DEBUG', false);
        define('WP_DEBUG_LOG', false);
        define('WP_DEBUG_DISPLAY', false);
        define('WP_CACHE', true);
        define('FORCE_SSL_ADMIN', true);
        define('DISALLOW_FILE_EDIT', true);
        define('AUTOMATIC_UPDATER_DISABLED', true);
    volumes:
      - wordpress_data:/var/www/html
      - wordpress_static:/var/www/html/wp-content
      - ./config/php-prod.ini:/usr/local/etc/php/conf.d/prod.ini
    depends_on:
      mysql:
        condition: service_healthy
    networks:
      - wordpress_network
    healthcheck:
      test:
        [
          'CMD',
          'curl',
          '-f',
          'http://localhost/wp-admin/install.php',
        ]
      interval: 30s
      timeout: 10s
      retries: 3

  mysql:
    image: mysql:8.0
    container_name: wp_mysql_prod
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
      - ./mysql/prod.cnf:/etc/mysql/conf.d/prod.cnf
    command: --default-authentication-plugin=mysql_native_password
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      timeout: 20s
      retries: 10
    networks:
      - wordpress_network

  redis:
    image: redis:7.0-alpine
    container_name: wp_redis_prod
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks:
      - wordpress_network

volumes:
  wordpress_data:
  wordpress_static:
  mysql_data:
  redis_data:

networks:
  wordpress_network:
    driver: bridge

本番環境用の Nginx 設定を作成します。

nginx# nginx/conf.d/wordpress.conf
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    root /var/www/html;
    index index.php index.html;

    # SSL設定
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

    # セキュリティヘッダー
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;

    # 静的ファイルのキャッシュ
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # PHP処理
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass wordpress:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    # WordPress パーマリンク
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
}

データベース連携設定

データベースの設定は、パフォーマンスとセキュリティの両方を考慮する必要があります。

MySQL の本番用設定ファイルを作成します。

ini# mysql/prod.cnf - 本番環境用MySQL設定
[mysqld]
# 基本設定
default-authentication-plugin=mysql_native_password
bind-address=0.0.0.0

# パフォーマンス設定
innodb_buffer_pool_size=1G
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=1
innodb_flush_method=O_DIRECT

# 接続設定
max_connections=200
max_allowed_packet=64M
thread_cache_size=50

# ログ設定
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2

# セキュリティ設定
skip-name-resolve
ssl-ca=/etc/mysql/ssl/ca.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem

データベース初期化用の SQL スクリプトを作成します。

sql-- mysql/init/01-init.sql
-- WordPress用データベースの初期設定

-- 文字セットの設定
ALTER DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- WordPress用ユーザーの権限設定
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX
ON wordpress.* TO 'wordpress'@'%';

-- セキュリティ強化用設定
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';

FLUSH PRIVILEGES;

WordPress の database.php でデータベース接続をカスタマイズできます。

php<?php
// wp-content/db.php - カスタムデータベース処理
class WP_Database_Connection {
    private $connection;

    public function __construct() {
        $this->connect();
    }

    private function connect() {
        $host = getenv('DB_HOST') ?: 'mysql';
        $port = getenv('DB_PORT') ?: 3306;
        $database = getenv('DB_NAME');
        $username = getenv('DB_USER');
        $password = getenv('DB_PASSWORD');

        $dsn = "mysql:host={$host};port={$port};dbname={$database};charset=utf8mb4";

        try {
            $this->connection = new PDO($dsn, $username, $password, [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
                PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
            ]);
        } catch (PDOException $e) {
            error_log('Database connection failed: ' . $e->getMessage());
            throw new Exception('Database connection failed');
        }
    }
}

SSL/HTTPS 対応

本番環境での SSL/HTTPS 対応は必須です。Let's Encrypt を使用した自動 SSL 証明書取得の設定を行います。

まず、SSL 証明書取得用のコンテナを追加します。

yaml# docker-compose.ssl.yml - SSL対応版
version: '3.8'

services:
  certbot:
    image: certbot/certbot
    container_name: wp_certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    command: certonly --webroot -w /var/www/certbot --force-renewal --email admin@example.com -d example.com --agree-tos

  nginx:
    image: nginx:alpine
    container_name: wp_nginx_ssl
    restart: unless-stopped
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    depends_on:
      - wordpress
    networks:
      - wordpress_network

SSL 証明書の自動更新用スクリプトを作成します。

bash#!/bin/bash
# scripts/renew-ssl.sh - SSL証明書自動更新

# 証明書の更新
docker-compose -f docker-compose.yml -f docker-compose.ssl.yml run --rm certbot renew

# Nginxの設定をリロード
docker-compose exec nginx nginx -s reload

# ログの記録
echo "SSL certificate renewal completed at $(date)" >> /var/log/ssl-renewal.log

Nginx の SSL 設定テンプレートを作成します。

nginx# nginx/templates/ssl.conf.template
server {
    listen 80;
    server_name ${DOMAIN_NAME};

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name ${DOMAIN_NAME};

    # SSL証明書の設定
    ssl_certificate /etc/letsencrypt/live/${DOMAIN_NAME}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN_NAME}/privkey.pem;

    # SSL最適化設定
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozTLS:10m;
    ssl_session_tickets off;

    # 最新のSSL設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=63072000" always;

    root /var/www/html;
    index index.php index.html;

    # WordPress設定
    include /etc/nginx/conf.d/wordpress-common.conf;
}

SSL 対応の WordPress 設定も追加します。

php<?php
// wp-config.php への追加設定

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

// SSL管理画面の強制
define('FORCE_SSL_ADMIN', true);

// プロキシ経由の場合のIP設定
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    $_SERVER['REMOTE_ADDR'] = trim($ips[0]);
}

図で SSL 対応の全体構成を表すと以下のようになります。

mermaidflowchart TB
    user[ユーザー] --> lb[ロードバランサー/CDN]
    lb --> nginx[Nginx :443]

    nginx --> wp[WordPress コンテナ]
    nginx --> static[静的ファイル]

    wp --> mysql[MySQL コンテナ]
    wp --> redis[Redis コンテナ]

    certbot[Certbot] --> letsencrypt[Let's Encrypt]
    letsencrypt --> ssl_cert[SSL証明書]
    ssl_cert --> nginx

    subgraph "SSL証明書管理"
        certbot
        letsencrypt
        ssl_cert
    end

    subgraph "Webアプリケーション"
        nginx
        wp
        static
    end

    subgraph "データ層"
        mysql
        redis
    end

    style ssl_cert fill:#90EE90
    style nginx fill:#87CEEB

この構成により、完全に SSL 対応された WordPress 環境が構築できます。証明書の自動更新機能により、運用負荷も大幅に軽減されます。

まとめ

Docker を活用した WordPress 環境の構築により、従来の課題を根本的に解決できることをご紹介しました。

開発・本番環境の差分をなくすことで、「私の環境では動く」問題や予期しないデプロイエラーが劇的に減少します。Docker Compose による統一された環境定義により、新しいチームメンバーでも数分で開発環境を立ち上げることができます。

マルチステージビルドによって、開発時の利便性と本番時の効率性を両立できました。環境変数を活用した設定管理により、機密情報を安全に管理しながら、同一のコードで複数の環境に対応可能です。

特に重要なポイントとして、以下の図で示すような運用フローが確立できます。

mermaidflowchart LR
    dev_code[開発コード] --> git[Git Repository]
    git --> ci[CI/CD Pipeline]
    ci --> test[自動テスト]
    test --> build[Docker Build]
    build --> registry[Container Registry]
    registry --> staging[ステージング環境]
    staging --> prod[本番環境]

    subgraph "品質保証"
        test
        staging
    end

    subgraph "デプロイメント"
        build
        registry
        prod
    end

    style test fill:#90EE90
    style staging fill:#87CEEB
    style prod fill:#FFB6C1

このワークフローにより、コードの品質を保ちながら、迅速で確実なデプロイが実現できます。

Docker による WordPress 環境構築は、初期の学習コストはありますが、中長期的には開発効率の大幅な向上とトラブルの減少をもたらします。環境差分による問題で悩んでいる方は、ぜひ今回ご紹介した方法を試してみてください。

継続的な改善により、より安定で効率的な WordPress 開発環境を構築できるでしょう。

関連リンク