【Docker】Nginx + PHP-FPMの環境をComposeで構築する手順

【Docker】Nginx + PHP-FPMの環境をComposeで構築する手順 Docker

NginxとPHP-FPMをDocker Composeで組み合わせると、本番に近い構成をローカルですばやく再現できます。Nginxが静的配信とリバースプロキシ、PHP-FPMがPHPの実行を担い、ソースはボリュームで共有します。ここでは最小構成から拡張のヒントまで、実務でそのまま使える形で手順をまとめます。

ディレクトリ構成を用意する

プロジェクト直下にCompose、Nginx設定、PHP用Dockerfileと設定、アプリの公開ディレクトリを並べます。public配下にindex.phpを置き、Nginxのドキュメントルートにします。

project/
├─ docker-compose.yml
├─ nginx/
│  └─ default.conf
├─ php/
│  ├─ Dockerfile
│  └─ php.ini
└─ public/
   └─ index.php

docker-compose.ymlを書く

NginxとPHP-FPMを同一ネットワークで接続し、ソースコードを両コンテナにマウントします。Nginxはホストのポートを公開し、PHP-FPMは内部で待ち受けるだけにします。

version: "3.9"

services:
  nginx:
    image: nginx:1.27-alpine
    container_name: app_nginx
    ports:
      - "8080:80"
    volumes:
      - ./public:/var/www/html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - php
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1/healthz || exit 1"]
      interval: 10s
      timeout: 3s
      retries: 5

  php:
    build:
      context: ./php
    container_name: app_php
    environment:
      PHP_IDE_CONFIG: "serverName=docker"
      TZ: "Asia/Tokyo"
    volumes:
      - ./public:/var/www/html
    healthcheck:
      test: ["CMD", "php", "-v"]
      interval: 30s
      timeout: 5s
      retries: 3

networks:
  default:
    name: app_net

Nginxの仮想ホスト設定を追加する

ドキュメントルートを/var/www/htmlにし、PHPはphpサービスの9000番へfastcgiで渡します。フロントコントローラ方式のフレームワークでも動くようtry_filesでindex.phpにフォールバックします。

server {
  listen 80;
  server_name localhost;

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

  location /healthz {
    access_log off;
    return 200 "ok";
    add_header Content-Type text/plain;
  }

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

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

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

  client_max_body_size 20m;
  sendfile on;
}

PHP-FPMのDockerfileを用意する

公式のphp:fpmイメージをベースに、よく使う拡張をインストールして設定をコピーします。必要に応じてpdo_mysqlなどを追加します。

# php/Dockerfile
FROM php:8.2-fpm-alpine

RUN apk add --no-cache icu-dev libpng-dev libjpeg-turbo-dev oniguruma-dev \
  && docker-php-ext-configure intl \
  && docker-php-ext-install -j$(nproc) intl opcache pdo pdo_mysql

COPY php.ini /usr/local/etc/php/conf.d/zzz-custom.ini

WORKDIR /var/www/html

USER www-data

PHPの設定を最小限整える

開発中はエラー表示を有効化し、タイムゾーンやOPcacheの基本設定を入れておきます。本番ではdisplay_errorsをオフに切り替えます。

; php/php.ini
date.timezone = Asia/Tokyo
memory_limit = 256M
upload_max_filesize = 20M
post_max_size = 21M
display_errors = On
error_reporting = E_ALL

opcache.enable=1
opcache.enable_cli=0
opcache.validate_timestamps=1
opcache.revalidate_freq=2

動作確認用のindex.phpを置く

PHPが実行されること、サーバー変数が正しく渡っていることを確認します。不要になったらアプリ本体に差し替えます。

<?php
header('Content-Type: text/plain; charset=utf-8');
echo "Hello from PHP-FPM on Docker\n";
echo "PHP: " . PHP_VERSION . "\n";
echo "Server: " . ($_SERVER['SERVER_SOFTWARE'] ?? 'n/a') . "\n";

起動と確認を行う

コンテナをビルドして立ち上げ、ブラウザでhttp://localhost:8080 にアクセスします。ログにエラーが出ていないかも確認します。

docker compose build
docker compose up -d
docker compose logs -f nginx
docker compose logs -f php

権限とパフォーマンスの勘所を押さえる

マウントしたソースの所有者はwww-dataで実行されます。開発環境では大半の操作が問題なく行えますが、キャッシュやアップロード先をpublic外の書き込み可能ディレクトリに分けると安全です。静的アセットはNginxが直接配信し、PHPは動的処理に集中させます。OPcacheはvalidate_timestampsで即時反映を優先し、本番ではrevalidate_freqを延ばして効率を上げます。

XdebugやSSLを加えるときの指針

ステップデバッグが必要になったらphp-fpmイメージにpeclでxdebugを追加し、remote_hostをhost.docker.internalへ向けます。ローカルでHTTPSが欲しいときはmkcertやtraefik/caddyをフロントに置く構成に切り替え、Nginxは上流リバースプロキシの背後で80番待ち受けとします。

よくあるトラブルへの対処

502 Bad Gatewayが出る場合はphpコンテナの起動状態とfastcgi_passのホスト名を見直します。ダウンロードダイアログになる場合はNginxのlocation ~ \.php のブロックが一致していない可能性があります。権限エラーはマウント先の書き込み権を確認し、必要に応じてキャッシュディレクトリのみパーミッションを緩めます。ポート競合が出たらComposeの公開ポートを変更します。

まとめと次の一歩

Nginxをフロント、PHP-FPMをアプリ実行に分離した二層構成は、本番を意識したローカル開発の定番です。Composeでサービスを定義し、Nginxのfastcgi設定とPHP-FPMの拡張・ini調整を最小限に整えれば、すぐに動く土台が完成します。この土台にデータベースやキャッシュ、キューなどを追加し、環境変数とボリュームの整理を進めると、より実践的なコンテナ開発環境が構築できます。