Nginx의 client_max_body_size를 올바르게 설정하는 방법 | 업로드 제한 문제 해결
Nginx에서 파일 업로드를 구현할 때, 「작은 파일은 전송되지만 큰 파일을 보내면 413 오류가 발생한다」는 문제는 매우 자주 마주칩니다. 그 원인은 거의 대부분 <code>client_max_body_size</code> 설정 부족입니다. 그러나 Nginx 설정만 수정해도 해결되지 않는 경우가 많으며, PHP의 <code>upload_max_filesize</code>와 <code>post_max_size</code>, 나아가 타임아웃 설정까지 포함한 총체적인 이해가 필요합니다. 본 문서에서는 업로드 제한과 관련된 모든 설정 항목을 체계적으로 설명합니다.
client_max_body_size의 기본값과 역할
Nginx에는 클라이언트로부터의 요청 본문 최대 크기를 제한하는 <code>client_max_body_size</code> 지시문이 있습니다. 기본값은 <code>1m</code> (1 MiB)입니다. 이 제한을 초과하는 요청은 즉시 <code>413 Request Entity Too Large</code> 오류로 거부됩니다.
기본값이 1m으로 매우 작기 때문에 이미지 한 장이나 PDF를 업로드해도 금방 상한에 도달합니다. 실제 프로덕션 환경에서는 용도에 따라 이 값을 적절히 높여야 합니다.
설정 장소: http / server / location의 차이
<code>client_max_body_size</code>는 Nginx의 설정 계층(http / server / location) 어디든지 작성할 수 있습니다. 더 구체적인 범위 설정이 우선됩니다.
# http ブロック(全サーバー共通)
http {
client_max_body_size 10m;
server {
listen 80;
server_name example.com;
# server ブロック(このバーチャルホスト全体)
client_max_body_size 50m;
location /upload {
# location ブロック(このパスのみ)
# より大きなファイルを許可したい場合
client_max_body_size 200m;
proxy_pass http://app;
}
location /api {
# APIエンドポイントはデフォルト(1m)のままにする例
client_max_body_size 1m;
}
}
}
업로드 전용 엔드포인트만 큰 값을 설정하고 나머지는 작은 값으로 유지하는 것이 보안 측면에서 바람직한 접근법입니다. <code>0</code>을 지정하여 무제한으로 할 수 있지만, DoS 공격 위험이 증가하므로 권장하지 않습니다.
413 Request Entity Too Large 에러의 원인과 해결
413 에러가 발생하는 원인과 대처법을 정리합니다.
| 원인 | 확인 항목 | 대처 방법 |
|---|---|---|
| Nginx 제한 초과 | nginx.conf의 <code>client_max_body_size</code> | 값 올리기 |
| PHP 제한 초과 | php.ini의 <code>upload_max_filesize</code> | 값 올리기 |
| POST 본문 전체 제한 초과 | php.ini의 <code>post_max_size</code> | upload_max_filesize 보다 크게 설정 |
| 리버스 프록시 제한 | 업스트림 Nginx 또는 로드 밸런서 설정 | 각 단계의 프록시 확인 |
Nginx 설정을 변경한 후에는 반드시 리로드가 필요합니다.
# 設定の文法チェック
nginx -t
# 設定のリロード(サービス停止なし)
nginx -s reload
# または systemd 経由
systemctl reload nginx
PHP의 upload_max_filesize / post_max_size와의 관계
Nginx의 <code>client_max_body_size</code>를 높이는 것만으로는 충분하지 않습니다. 백엔드가 PHP인 경우 PHP 레벨에서도 독립적인 제한이 있습니다. 이 3가지 설정이 모두 적절한 값으로 설정되어야만 업로드가 성공합니다.
; php.ini の設定
; 1ファイルあたりの上限
upload_max_filesize = 100M
; POSTリクエスト全体の上限(upload_max_filesize より大きくする)
; multipart/form-data のオーバーヘッド分を見込んで多めに設定
post_max_size = 110M
; メモリ上限(post_max_size より大きくする)
memory_limit = 256M
; アップロード処理の実行時間(大容量ファイル用に延ばす)
max_execution_time = 300
max_input_time = 300
중요한 설정값의 관계는 다음과 같습니다.
- client_max_body_size(Nginx) ≥ post_max_size(PHP) ≥ upload_max_filesize(PHP)
- Nginx가 요청을 거부하면 처리가 PHP까지 도달하지 않습니다
- <code>post_max_size</code>는 복수 파일 업로드와 파일 이외의 폼 필드도 포함한 POST 바디 전체의 크기 제한
proxy_read_timeout / proxy_send_timeout 의 중요성
대용량 파일 업로드 시에는 타임아웃 설정이 중요합니다. 기본 <code>proxy_read_timeout</code>은 60초이며, 업로드에 시간이 걸리면 처리가 중단됩니다.
location /upload {
client_max_body_size 500m;
proxy_pass http://app_backend;
# バックエンドからのレスポンス待機時間
# 大容量ファイルの処理には長めに設定
proxy_read_timeout 600s;
# クライアントへのデータ送信待機時間
proxy_send_timeout 600s;
# バックエンドへの接続タイムアウト
proxy_connect_timeout 60s;
# クライアントのリクエストボディ受信タイムアウト
# 2回の連続した読み取り操作の間の時間
client_body_timeout 120s;
}
업로드 엔드포인트와 일반 API 엔드포인트에 대해 서로 다른 타임아웃 값을 설정할 것을 권장합니다.
Docker에서의 설정(nginx.conf 마운트)
Docker 환경에서는 커스텀 nginx.conf 또는 conf.d 파일을 컨테이너에 마운트하여 설정을 반영합니다.
# Dockerfile でのカスタム設定追加
FROM nginx:alpine
# カスタム設定ファイルをコピー
COPY ./nginx/conf.d/upload.conf /etc/nginx/conf.d/upload.conf
# デフォルト設定を完全に置き換える場合
# COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
# docker-compose.yml でのボリュームマウント
version: '3.8'
services:
nginx:
image: nginx:alpine
volumes:
# ディレクトリごとマウント(変更が即反映される)
- ./nginx/conf.d:/etc/nginx/conf.d
# または特定ファイルだけマウント
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
# nginx/conf.d/upload.conf
server {
listen 80;
server_name localhost;
# グローバルのアップロード上限
client_max_body_size 100m;
location / {
proxy_pass http://app:9000;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
location /upload {
client_max_body_size 500m;
proxy_pass http://app:9000;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
설정 확인 명령어
현재 Nginx 설정에서 <code>client_max_body_size</code>의 값을 확인하려면, <code>nginx -T</code>로 모든 설정을 전개한 후 grep으로 검색하는 것이 편리합니다.
# 全設定を展開して client_max_body_size を検索
nginx -T | grep -i body_size
# 出力例:
# client_max_body_size 1m; ← デフォルト(http ブロック)
# client_max_body_size 100m; ← カスタム設定(server ブロック)
# 設定ファイルのパスも確認
nginx -T | grep "# configuration"
# 特定の設定ファイルだけチェック
nginx -t -c /etc/nginx/nginx.conf
# 現在読み込まれている設定のダンプ
nginx -T 2>/dev/null | grep -A1 "client_max"
일반적인 설정 오류 및 해결 방법
- <strong>단위 오류</strong>: <code>client_max_body_size 100</code>은 바이트로 지정됩니다. <code>100m</code>처럼 반드시 단위를 붙이세요
- <strong>계층 간과</strong>: location 블록 내에서 상위에 있는 server 블록이나 http 블록이 적용되고 있는 경우
- <strong>리로드 잊음</strong>: 설정 파일을 변경해도 <code>nginx -s reload</code>를 실행하지 않으면 적용되지 않습니다
- <strong>여러 server 블록</strong>: include로 읽어들인 다른 conf.d 파일이 충돌하고 있습니다
- <strong>PHP와의 불일치</strong>: Nginx를 올려도 PHP의 <code>upload_max_filesize</code>가 낮은 まま이면 413 외의 오류 발생
이 기사에서 사용할 수 있는 테스트 파일 (무료)
- → <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">경계값 테스트 파일 목록</a> — client_max_body_size 설정값 전후의 파일로 오류 재현
- → <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG 테스트 이미지 목록</a> — 다양한 크기의 PNG로 Nginx 제한 확인
관련 기사
- → <a href="/ja/blog/how-to-test-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">파일 업로드 제한을 올바르게 테스트하는 방법</a>
- → <a href="/ja/blog/multipart-form-data-overhead/" class="text-primary-600 dark:text-primary-400 hover:underline">multipart/form-data 의 오버헤드를 정확하게 계산하기</a>
- → <a href="/ja/blog/mb-vs-mib-file-size/" class="text-primary-600 dark:text-primary-400 hover:underline">MB 와 MiB 의 차이|파일 크기 단위의 올바른 이해</a>