コンテンツにスキップ

DockerでPHPのファイルアップロード設定をする方法|php.ini・Nginx・docker-compose

カテゴリ:Docker・PHP

Dockerで構築した環境では「ローカルで設定したはずなのにコンテナで反映されない」「Nginxコンテナを直したが PHP-FPMコンテナの設定が残っている」といった問題が起きやすいです。これは、Dockerコンテナが独立した環境を持つため、設定ファイルがホストとコンテナで分離されているためです。本記事では、NginxコンテナとPHP-FPMコンテナの組み合わせで、ファイルアップロード設定を正しく行う方法を体系的に解説します。

DockerでのPHPカスタム設定方法

PHP コンテナに独自の php.ini 設定を反映させる方法は主に2つあります。Dockerfile でイメージビルド時にファイルをコピーする方法と、docker-compose でボリュームマウントを使う方法です。

方法1: Dockerfile でphp.iniをコピー

# Dockerfile(PHP-FPM コンテナ)
FROM php:8.3-fpm-alpine

# 必要な拡張をインストール
RUN docker-php-ext-install pdo_mysql opcache

# カスタム php.ini をコンテナにコピー
# php.ini-development または php.ini-production をベースにする
COPY ./docker/php/php.ini /usr/local/etc/php/php.ini

# または conf.d ディレクトリに追加設定ファイルとして置く(推奨)
# 既存設定を上書きせず、変更したい値だけ記述できる
COPY ./docker/php/custom.ini /usr/local/etc/php/conf.d/99-custom.ini

WORKDIR /var/www/html

方法2: docker-compose でボリュームマウント

# docker-compose.yml
services:
  php:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
    volumes:
      # アプリのソースコード
      - ./src:/var/www/html
      # php.ini をマウント(ファイル変更が即反映される)
      - ./docker/php/custom.ini:/usr/local/etc/php/conf.d/99-custom.ini:ro

ボリュームマウント方式は開発環境に向いており、設定ファイルを変更してコンテナを再起動するだけで反映できます。本番環境はイメージにコピーする Dockerfile 方式が推奨されます(イメージの再現性が保たれるため)。

必要な設定値と php.ini の書き方

ファイルアップロードに関連する設定値は4つあります。これらをまとめて設定した custom.ini ファイルを用意します。

; docker/php/custom.ini
; ============================================
; ファイルアップロード関連の設定
; ============================================

; ファイルアップロードを有効化(デフォルトOnだが明示する)
file_uploads = On

; 1ファイルあたりのアップロード上限
; Nginx の client_max_body_size と合わせること
upload_max_filesize = 100M

; POSTリクエスト全体の上限
; upload_max_filesize より大きくすること(フォームフィールドのオーバーヘッド分)
post_max_size = 110M

; ============================================
; メモリ・実行時間の設定
; ============================================

; PHPスクリプトが使用できる最大メモリ
; post_max_size より大きくすること
memory_limit = 256M

; スクリプトの最大実行時間(秒)
; 大きなファイルのアップロードや処理に対応
max_execution_time = 300

; リクエストデータ(POSTやファイル)の読み込み最大時間(秒)
; -1 で max_execution_time に従う
max_input_time = 300

php.ini の設定ファイルの場所を確認する方法

コンテナ内でどの php.ini が読み込まれているか確認するには、以下のコマンドを使います。

# コンテナ内で実行(docker exec 経由)
docker exec -it <コンテナ名> php -i | grep "php.ini"

# 出力例:
# Configuration File (php.ini) Path => /usr/local/etc/php
# Loaded Configuration File         => /usr/local/etc/php/php.ini

# Additional .ini files parsed(conf.d の追加設定)
docker exec -it <コンテナ名> php -i | grep "additional"
# Additional .ini files parsed => /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini,
#   /usr/local/etc/php/conf.d/99-custom.ini

# 特定の設定値を確認
docker exec -it <コンテナ名> php -i | grep -E "upload_max|post_max|memory_limit"
# upload_max_filesize => 100M
# post_max_size       => 110M
# memory_limit        => 256M

Web 経由で確認する場合は phpinfo() を使います。

<?php
// /var/www/html/public/info.php (一時的なデバッグ用)
phpinfo();
// ※ 本番環境では削除すること(サーバー情報が丸見えになる)

NginxコンテナとPHP-FPMコンテナ間の設定の関係

Docker の典型的な PHP 構成は Nginx コンテナと PHP-FPM コンテナを分離する2コンテナ構成です。それぞれが独立した制限を持つため、両方の設定が適切でないとアップロードは失敗します

クライアント
    │
    ▼(HTTP リクエスト)
┌──────────────────────────────┐
│  Nginx コンテナ              │  ← client_max_body_size で制限
│  client_max_body_size 100m;  │     ここを超えると 413 エラー
└──────────────────────────────┘
    │
    ▼(FastCGI プロトコル)
┌──────────────────────────────┐
│  PHP-FPM コンテナ            │  ← upload_max_filesize / post_max_size で制限
│  upload_max_filesize = 100M  │     ここを超えると UPLOAD_ERR_INI_SIZE
│  post_max_size = 110M        │
└──────────────────────────────┘
# docker/nginx/conf.d/default.conf
server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php;

    # Nginx レベルのアップロード上限
    # PHP の upload_max_filesize / post_max_size 以上にする
    client_max_body_size 110m;

    # タイムアウト設定(大容量ファイル処理用)
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;

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

    location ~ \.php$ {
        fastcgi_pass php:9000;   # PHP-FPMコンテナのサービス名:ポート
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;

        # FastCGI のタイムアウト設定
        fastcgi_read_timeout 300s;
        fastcgi_send_timeout 300s;
    }
}

docker-compose.yml の完全な設定例

Nginx + PHP-FPM + ボリュームマウントを含む完全な docker-compose.yml の例を示します。

version: '3.8'

services:
  # Nginx コンテナ
  nginx:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    volumes:
      # アプリのソースコード(Nginx から静的ファイルを配信)
      - ./src:/var/www/html/public:ro
      # Nginx 設定ファイル
      - ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
    depends_on:
      - php
    networks:
      - app-network

  # PHP-FPM コンテナ
  php:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
    volumes:
      # アプリのソースコード
      - ./src:/var/www/html
      # PHP カスタム設定(開発時はマウントで即反映)
      - ./docker/php/custom.ini:/usr/local/etc/php/conf.d/99-custom.ini:ro
      # アップロードファイルの一時保存先(権限に注意)
      - upload_tmp:/tmp/php-uploads
    environment:
      PHP_UPLOAD_TMP_DIR: /tmp/php-uploads
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

volumes:
  upload_tmp:
    driver: local
# docker/php/Dockerfile
FROM php:8.3-fpm-alpine

# 必要なシステムパッケージ
RUN apk add --no-cache \
    libpng-dev \
    libjpeg-turbo-dev \
    libwebp-dev \
    freetype-dev

# PHP 拡張のインストール
RUN docker-php-ext-configure gd \
        --with-freetype \
        --with-jpeg \
        --with-webp && \
    docker-php-ext-install \
        gd \
        pdo_mysql \
        opcache \
        exif

# アプリユーザーを作成(www-data と権限を合わせる)
RUN addgroup -g 1000 appuser && \
    adduser -u 1000 -G appuser -s /bin/sh -D appuser

USER appuser
WORKDIR /var/www/html

設定が反映されているか確認する方法

設定変更後は必ずコンテナを再起動し、設定が正しく読み込まれているか確認します。

# コンテナの再起動(設定ファイル変更を反映)
docker compose restart php

# または特定の設定値だけ確認
docker compose exec php php -r "echo ini_get('upload_max_filesize'), PHP_EOL;"
docker compose exec php php -r "echo ini_get('post_max_size'), PHP_EOL;"
docker compose exec php php -r "echo ini_get('memory_limit'), PHP_EOL;"

# 複数の値をまとめて確認
docker compose exec php php -r "
foreach (['upload_max_filesize', 'post_max_size', 'memory_limit', 'max_execution_time'] as \$key) {
    echo \$key . ' = ' . ini_get(\$key) . PHP_EOL;
}"

# Nginx の設定確認
docker compose exec nginx nginx -T | grep -E "client_max_body|server_name"

# Nginx の設定をリロード(コンテナ再起動なし)
docker compose exec nginx nginx -s reload

よくあるトラブルと解決法

症状 原因 解決法
413 Request Entity Too Large Nginx の client_max_body_size 超過 Nginx 設定を引き上げ、nginx -s reload
PHPレベルで UPLOAD_ERR_INI_SIZE upload_max_filesize 超過 custom.ini を修正してコンテナ再起動
設定を変更しても反映されない コンテナ再起動が必要 / 設定ファイルのマウントパスが間違い docker compose restart php / パスを確認
一時ディレクトリへの書き込み失敗 PHP コンテナのユーザー権限と /tmp のパーミッション不一致 ボリュームの権限設定や upload_tmp_dir を確認
大容量ファイルでタイムアウト fastcgi_read_timeoutmax_execution_time が短い 両方の値を引き上げる

本番環境向けの補足

本番環境では以下の点も考慮してください。

  • php.ini はイメージビルド時に COPY で組み込み、ボリュームマウントしない(再現性のため)
  • display_errors = Offlog_errors = On を必ず設定する
  • アップロード先を S3 などのクラウドストレージにする場合、コンテナローカルへの一時保存はリクエスト処理中のみに留める
  • 複数レプリカ(水平スケール)構成では、ローカルのアップロード先は使えない。S3や共有ストレージ(EFS・NFS)を使う
  • PHP-FPM のプロセス数(pm.max_children)も大容量アップロードが同時多数発生するとメモリを圧迫する

この記事で使えるテストファイル(無料)

よくある質問

DockerでPHPのupload_max_filesizeを変更するには?

カスタムphp.iniファイルを作成し、Dockerfileでコンテナ内の/usr/local/etc/php/conf.d/にコピーします。

docker-compose.ymlでNginxとPHP-FPMのアップロード設定をするには?

Nginx用のnginx.confにclient_max_body_sizeを設定し、PHP用のphp.iniにupload_max_filesizeを設定して、それぞれvolumesでマウントします。

Docker環境でアップロード設定が反映されないのはなぜ?

php.iniの設置先が間違っている可能性があります。php -i | grep upload_max_filesizeで現在の設定値を確認し、Loaded Configuration Fileでどのiniが読まれているか確認してください。

📚 関連記事

PNG vs WebP vs AVIF|画像フォーマットの選び方と変換方法

PNG / JPEG / WebP / AVIF の特徴・用途・ブラウザ対応状況を比較。picture 要素での出し分け、DevLab の画像フォーマット変換ツールの使い方も解説。

2026-04-18

Whois でドメイン情報を調べる方法|有効期限・ネームサーバー・登録者

Whois でわかること (登録者・有効期限・レジストラ・NS)、GDPR によるプライバシー保護の影響、ドメイン管理の実務的な使い方を解説。

2026-04-18

HTTP ステータスコード完全ガイド|よくあるエラーの原因と対処法

開発者が頻出する HTTP ステータスコード (200/301/302/400/401/403/404/413/422/429/500/502/503/504) の意味・原因・対処法を解説。301 vs 302 の SEO 影響、400 vs 422 の使い分けも。

2026-04-18

cURL コマンドを JavaScript fetch・Python requests に変換する方法|DevTools 連携

Chrome DevTools の Copy as cURL を fetch / axios / Python requests / PHP cURL / Go net/http に変換する手順を解説。主要 cURL オプション (-X / -H / -d / -F / -u / -b / -L) の変換パターン、認証トークンの扱い、注意点まで。

2026-04-16

Cookie のセキュリティフラグ完全ガイド|Secure / HttpOnly / SameSite / __Host-

Cookie のセキュリティ属性 Secure / HttpOnly / SameSite (Strict/Lax/None) / __Host- __Secure- プレフィックス / 4096 バイト制限を解説。CSRF / XSS / セッションハイジャック対策と、Laravel / Express の実装例。

2026-04-16

JWT のセキュリティベストプラクティス|alg none 攻撃 / 有効期限 / 署名検証

JWT (JSON Web Token) の代表的な脆弱性 6 種類 (alg none 攻撃 / 鍵混同 / 無期限トークン / payload への機密情報 / 失効不可 / 弱いシークレット) と対策。リフレッシュトークンパターン、失効リスト、HttpOnly Cookie 格納まで。

2026-04-16