413 Request Entity Too Largeエラーの原因と解決方法|Nginx・PHP・Apache完全対応
ファイルアップロード機能を実装していると、突然ブラウザに「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_size が 1MB に設定されています。画像や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、バイト単位) |
この記事で使えるテストファイル(無料)
- → 10MB境界値テストPNG — Nginxデフォルト上限(1MB)超えのテストに
- → 50MB境界値テストPNG — upload_max_filesize 上限テストに
- → 境界値テスト用ファイル一覧 — さまざまなサイズの境界値テストファイル
- → 1MBテストPNG画像 — 小さいサイズでの動作確認に