コンテンツにスキップ

413 Request Entity Too Largeエラーの原因と解決方法|Nginx・PHP・Apache完全対応

カテゴリ:サーバー・HTTP

ファイルアップロード機能を実装していると、突然ブラウザに「413 Request Entity Too Large」というエラーが表示されることがあります。このエラーは、送信したリクエストボディのサイズがサーバー側で設定されている上限値を超えたときに返される HTTP ステータスコードです。本記事では Nginx・PHP・Apache それぞれの設定箇所を網羅し、原因の特定から解決までを体系的に解説します。

413エラーとは何か

HTTP 413 ステータスコード(RFC 9110 では「Content Too Large」に改名)は、クライアントが送信したリクエストボディがサーバーの処理可能なサイズを超えている場合に返されます。ファイルアップロードに限らず、大きな JSON ペイロードや Base64 エンコードされたデータの送信でも発生します。

このエラーが発生すると、サーバーはリクエスト自体を拒否するため、アプリケーション側のコード(PHPやPython等)に処理が到達する前に接続が切断されます。そのため、アプリケーションログには記録が残らず、Web サーバーのエラーログを確認する必要があります。

Nginx: client_max_body_size の設定

Nginx はデフォルトで client_max_body_size1MB に設定されています。画像やPDFのアップロードを受け付けるサイトでは、ほぼ確実にこの値を引き上げる必要があります。

# /etc/nginx/nginx.conf(グローバル設定)
http {
    # すべての仮想ホストに適用
    client_max_body_size 100m;

    server {
        listen 80;
        server_name example.com;

        # このサーバーブロック内のみに適用(httpの値を上書き)
        client_max_body_size 50m;

        location /api/upload {
            # このlocationのみに適用(serverの値を上書き)
            client_max_body_size 200m;

            proxy_pass http://backend;
        }
    }
}

設定の優先順位は location > server > http の順です。特定のアップロードエンドポイントだけ上限を大きくしたい場合は、location ブロックで指定するのがベストプラクティスです。

# 設定変更後はNginxをリロード
sudo nginx -t          # 構文チェック
sudo systemctl reload nginx  # リロード(ダウンタイムなし)

# エラーログの確認
tail -f /var/log/nginx/error.log
# 413エラー時のログ例:
# client intended to send too large body: 10485760 bytes

PHP: upload_max_filesize / post_max_size / memory_limit の関係

PHP には複数のサイズ制限があり、それぞれの関係を正しく理解する必要があります。以下の不等式を常に満たすように設定してください。

; php.ini の設定
; 必ず以下の関係を維持すること:
; upload_max_filesize <= post_max_size <= memory_limit

; 1ファイルあたりの最大サイズ
upload_max_filesize = 50M

; POSTリクエスト全体の最大サイズ(複数ファイルの合計 + フォームデータ)
post_max_size = 100M

; PHPスクリプトが使用できる最大メモリ
memory_limit = 256M

; ファイルアップロードの最大数
max_file_uploads = 20

; アップロードの一時保存先
upload_tmp_dir = /tmp
ディレクティブ デフォルト値 影響範囲
upload_max_filesize 2M 1ファイルの最大サイズ
post_max_size 8M POSTリクエスト全体(ファイル+フォームデータ)
memory_limit 128M スクリプト実行時の最大メモリ使用量
max_file_uploads 20 同時アップロード可能なファイル数
max_execution_time 30 スクリプト実行の最大秒数(大容量ファイルは延長が必要)
max_input_time 60 入力データの解析にかけられる最大秒数
// 現在のPHP設定値を確認するスクリプト
echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . PHP_EOL;
echo 'post_max_size: '       . ini_get('post_max_size') . PHP_EOL;
echo 'memory_limit: '        . ini_get('memory_limit') . PHP_EOL;
echo 'max_file_uploads: '    . ini_get('max_file_uploads') . PHP_EOL;
echo 'max_execution_time: '  . ini_get('max_execution_time') . PHP_EOL;

// php.ini の場所を確認
echo 'Loaded php.ini: ' . php_ini_loaded_file() . PHP_EOL;

Apache: LimitRequestBody の設定

Apache では LimitRequestBody ディレクティブでリクエストボディの上限を設定します。デフォルトは 0(無制限)ですが、セキュリティのために適切な上限を設定することが推奨されます。

# /etc/apache2/apache2.conf または .htaccess
# バイト単位で指定(100MB = 104857600 bytes)

# グローバル設定
LimitRequestBody 104857600

# 特定のディレクトリのみ
<Directory "/var/www/html/uploads">
    LimitRequestBody 209715200
</Directory>

# 特定のURLパスのみ
<Location "/api/upload">
    LimitRequestBody 209715200
</Location>

# .htaccess での設定(AllowOverride が必要)
# php_value upload_max_filesize 50M
# php_value post_max_size 100M

よくある組み合わせミス

413エラーの厄介な点は、複数のレイヤーにそれぞれ上限設定があることです。1つの設定を変更しても別のレイヤーでブロックされるケースが頻繁に発生します。

ケース1: Nginx は通過するが PHP で拒否される

Nginx の client_max_body_size を 100m に設定したにもかかわらず、PHP の upload_max_filesize が 2M のままだと、50MBのファイルは Nginx を通過しますが PHP 側で無視されます。この場合、HTTP ステータスは 200 を返しますがファイルは空になり、$_FILES にエラーコード 1(UPLOAD_ERR_INI_SIZE)がセットされます。

ケース2: upload_max_filesize は十分だが post_max_size が足りない

upload_max_filesize = 50M に設定していても、post_max_size = 8M のままだと、8MBを超えるリクエスト全体が破棄されます。この場合、$_POST$_FILES が両方とも空配列になるという分かりにくい挙動になります。

ケース3: リバースプロキシ構成での見落とし

Nginx をリバースプロキシとして使い、バックエンドに Apache + PHP-FPM を配置している場合、Nginx・Apache・PHP の全てで上限を設定する必要があります。

# Nginx リバースプロキシの設定
server {
    client_max_body_size 100m;

    location / {
        proxy_pass http://127.0.0.1:8080;

        # プロキシ関連のタイムアウトも延長(大容量ファイル対策)
        proxy_read_timeout 300;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;

        # バッファリングの設定
        proxy_request_buffering on;
        proxy_buffering on;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
    }
}

デバッグ手順

413エラーが発生したときは、以下の手順で原因を特定します。

# 1. どのレイヤーでブロックされているか確認
# Nginx のエラーログを確認
tail -n 50 /var/log/nginx/error.log | grep "too large"

# 2. PHP の設定値を確認
php -i | grep -E "upload_max|post_max|memory_limit"

# 3. PHP-FPM の設定ファイルを確認(php.ini とは別の場合がある)
php-fpm -i | grep -E "upload_max|post_max"
# または
find /etc -name "php.ini" -o -name "www.conf" | xargs grep -l "upload_max"

# 4. Apache の設定を確認
apachectl -t -D DUMP_RUN_CFG 2>/dev/null | grep -i limit
grep -r "LimitRequestBody" /etc/apache2/ /etc/httpd/

# 5. curl で実際にテスト(10MBのダミーファイルを送信)
dd if=/dev/zero of=/tmp/test_10mb.bin bs=1M count=10
curl -v -X POST -F "file=@/tmp/test_10mb.bin" https://example.com/api/upload

# 6. レスポンスヘッダーを確認
curl -I -X POST -F "file=@/tmp/test_10mb.bin" https://example.com/api/upload

テスト方法

設定変更後は、実際にサイズの異なるファイルをアップロードしてテストすることが重要です。DevLab では境界値テスト用のファイルを提供しています。上限値の前後(例: 上限が50MBなら49MB・50MB・51MB)でテストし、期待どおりの挙動になるか確認してください。

# JavaScript での送信テスト例
# 指定サイズのBlobを作成して送信する方法

# <script>
# async function testUpload(sizeMB) {
#     const blob = new Blob(
#         [new ArrayBuffer(sizeMB * 1024 * 1024)],
#         { type: 'application/octet-stream' }
#     );
#     const formData = new FormData();
#     formData.append('file', blob, 'test.bin');
#
#     const response = await fetch('/api/upload', {
#         method: 'POST',
#         body: formData
#     });
#     console.log(sizeMB + 'MB:', response.status, response.statusText);
# }
#
# // 境界値テスト
# testUpload(1);    // 1MB  - 通常は成功
# testUpload(10);   // 10MB - 設定による
# testUpload(50);   // 50MB - 設定による
# testUpload(100);  // 100MB - 通常は失敗
# </script>

各サーバーの推奨設定まとめ

レイヤー ディレクティブ 推奨値(50MBアップロード対応)
Nginx client_max_body_size 60m(余裕を持たせる)
PHP upload_max_filesize 50M
PHP post_max_size 55M(upload_max_filesize より大きく)
PHP memory_limit 256M
Apache LimitRequestBody 62914560(60MB、バイト単位)

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

📚 関連記事

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