시스템 관리_27 Nginx 및 아파치 HTTP 413 Request Entity Too Large 요청 본문 크기 초과 오류 원인과 완벽 해결 가이드

 
  • 출처 / 참고: Nginx Official Documentation (ngx_http_core_module - client_max_body_size), Apache HTTP Server Documentation (core - LimitRequestBody), RFC 7231 (HTTP/1.1 Semantics and Content)

명령어: curl, nginx -T, apachectl, httpd, grep, tail
키워드: HTTP 413, Request Entity Too Large, Payload Too Large, client_max_body_size, LimitRequestBody, upload_max_filesize, post_max_size
사용처: 웹 애플리케이션 대용량 파일 첨부 및 REST API 요청 시 본문 크기 제한으로 인한 업로드 차단 해제


실행예제

웹 애플리케이션으로 대용량 파일 업로드 또는 큰 JSON 페이로드 전송 시 웹 서버(Nginx / Apache)가 413 Request Entity Too Large(또는 HTTP/2 이상에서 413 Payload Too Large)를 즉시 반환하는 상태를 진단하고 에러 로그 및 현재 설정값을 점검합니다.

# 1. 클라이언트 관점: 특정 크기(예: 10MB)의 더미 파일을 생성하여 파일 업로드 요청 테스트
$ dd if=/dev/zero of=test_10mb.bin bs=1M count=10
$ curl -v -F "file=@test_10mb.bin" https://example.com/upload
* Connected to example.com (192.168.1.100) port 443
> POST /upload HTTP/1.1
> Content-Length: 10486016
< HTTP/1.1 413 Request Entity Too Large
< Server: nginx
# -> 파일 전송 직후 웹 서버 레벨에서 413 에러를 즉각 반환하는지 확인

# 2. Nginx 에러 로그에서 413 관련 메시지 확인
$ sudo tail -n 20 /var/log/nginx/error.log
# [출력 예시]
# [error] 18452#18452: *412 client intended to send too large body: 10485760 bytes, client: 203.0.113.10, server: example.com, request: "POST /upload HTTP/1.1", host: "example.com"

# 3. Apache 에러 로그에서 413/LimitRequestBody 관련 메시지 확인
$ sudo tail -n 20 /var/log/apache2/error.log  # 또는 /var/log/httpd/error_log
# [출력 예시]
# [core:error] [pid 1234:tid 1402] Request body exceeds LimitRequestBody limit (10485760 bytes)

# 4. 현재 Nginx 전체 설정에서 client_max_body_size 지시어 확인 (기본값은 1m)
$ sudo nginx -T 2>/dev/null | grep -E "client_max_body_size"
# 아무것도 출력되지 않는다면 Nginx 기본값인 1MB로 엄격하게 제한 중인 상태임

# 5. 현재 Apache 설정에서 LimitRequestBody 지시어 검색
$ sudo grep -rnE "LimitRequestBody" /etc/apache2/ /etc/httpd/ 2>/dev/null

   

스크립트

현재 시스템에 설치된 웹 서버(Nginx / Apache)와 백엔드(PHP-FPM)의 설정 파일을 탐색하여 본문/업로드 크기 제한 지시어의 현재 설정값을 추출 및 비교하고 누락 여부를 진단하는 쉘 스크립트입니다.

#!/bin/bash
# check_upload_limits.sh - Diagnose HTTP 413 Request Entity Too Large limits across Web & WAS

echo "=========================================="
echo " [HTTP 413 본문 업로드 제한 진단]"
echo "=========================================="

# 1. Nginx 본문 크기 제한 점검
echo -e "\n[1] Nginx 'client_max_body_size' 설정 점검:"
if command -v nginx &>/dev/null; then
    NGINX_BODY_LIMITS=$(nginx -T 2>/dev/null | grep -rnE "client_max_body_size" | grep -v "#")
    if [ -n "$NGINX_BODY_LIMITS" ]; then
        echo "  [설정됨] 명시적인 client_max_body_size 설정 내역:"
        echo "$NGINX_BODY_LIMITS" | sed 's/^/    /'
    else
        echo "  [주의] client_max_body_size 지시어가 설정되어 있지 않습니다."
        echo "  -> Nginx 기본값인 1MB(1m)가 적용되어 1MB 초과 업로드 시 413 발생"
    fi
else
    echo "  - Nginx가 설치되어 있지 않습니다."
fi

# 2. Apache 본문 크기 제한 점검
echo -e "\n[2] Apache 'LimitRequestBody' 설정 점검:"
APACHE_CONF_DIR=""
[ -d "/etc/apache2" ] && APACHE_CONF_DIR="/etc/apache2"
[ -d "/etc/httpd" ] && APACHE_CONF_DIR="/etc/httpd"

if [ -n "$APACHE_CONF_DIR" ]; then
    APACHE_LIMITS=$(grep -rnE "LimitRequestBody" "$APACHE_CONF_DIR" 2>/dev/null | grep -v "#")
    if [ -n "$APACHE_LIMITS" ]; then
        echo "  [설정됨] Apache LimitRequestBody 설정 내역 (단위: Bytes):"
        echo "$APACHE_LIMITS" | sed 's/^/    /'
    else
        echo "  [기본값 사용 중] LimitRequestBody 기본값 0(무제한) 또는 1GB(배포판별 상이) 적용 중"
    fi
else
    echo "  - Apache 설정 디렉터리를 찾을 수 없습니다."
fi

# 3. PHP 환경 점검 (설치된 경우 백엔드 업로드 제한 확인)
echo -e "\n[3] 백엔드(PHP) 업로드 관련 제한 점검:"
if command -v php &>/dev/null; then
    UPLOAD_MAX=$(php -r 'echo ini_get("upload_max_filesize");')
    POST_MAX=$(php -r 'echo ini_get("post_max_size");')
    MEM_LIMIT=$(php -r 'echo ini_get("memory_limit");')
    
    echo "  - upload_max_filesize : ${UPLOAD_MAX} (단일 파일 최대 용량)"
    echo "  - post_max_size       : ${POST_MAX} (전체 POST 본문 최대 용량)"
    echo "  - memory_limit        : ${MEM_LIMIT} (스크립트 실행 메모리)"
    echo "  -> Nginx 제한을 늘려도 위 PHP 설정값이 작으면 파일 저장 시 백엔드 오류 발생"
else
    echo "  - PHP CLI가 감지되지 않아 백엔드 검사를 건너뜁니다."
fi

echo -e "\n=========================================="
echo " [진단 완료]"
echo "=========================================="

   

해설

HTTP 413 Request Entity Too Large 오류는 클라이언트가 웹 서버로 보낸 HTTP 요청의 Content-Length 또는 실제 바이트 스트림 크기가 웹 서버 설정 파일에 허용된 최대 본문 크기를 초과했을 때 발생합니다.

1. 주요 발생 원인

  1. Nginx의 client_max_body_size 기본값(1MB):
    • Nginx의 기본 허용 본문 용량은 단 1m입니다. 이미지, PDF, 엑셀 등 조금이라도 큰 파일을 업로드하면 Nginx가 요청 본문을 읽는 즉시 통신을 중단하고 413 응답을 반환합니다.
  2. Apache의 LimitRequestBody 바이트 제한:
    • 기본값은 0(무제한) 또는 배포판 기본 설정(보통 1GB)이나, 보안 강화 목적으로 512KB나 1MB 등 작은 바이트 단위로 지정되어 있는 경우 초과 패킷이 차단됩니다.
  3. 리버스 프록시와 백엔드 WAS 간 설정 불일치:
    • 스프링 부트(spring.servlet.multipart.max-file-size)나 PHP-FPM(upload_max_filesize)은 50MB로 설정해 두었으나, 앞단 Nginx가 1MB로 유지되어 애플리케이션 계층까지 도달하지 못하고 앞단에서 413 에러를 뱉는 경우입니다.

2. 단계별 해결 방법

1) Nginx 설정 수정 (client_max_body_size)

Nginx에서는 http, server, 또는 특정 업로드 location 블록에 허용할 최대 용량을 선언합니다.

# /etc/nginx/nginx.conf 또는 /etc/nginx/conf.d/*.conf

http {
    # 모든 가상 호스트 공통 적용 (예: 50MB)
    client_max_body_size 50M;

    server {
        server_name example.com;

        # 특정 업로드 엔드포인트만 대용량(예: 500MB) 허용 시
        location /api/upload {
            client_max_body_size 500M;
            proxy_pass http://127.0.0.1:8080;
        }
    }
}
  • 무제한 설정: client_max_body_size 0;으로 지정하면 검사를 비활성화할 수 있으나 보안상 권장하지 않습니다.
  • 수정 후 반영:
    sudo nginx -t && sudo systemctl reload nginx
    

2) Apache 설정 수정 (LimitRequestBody)

Apache에서는 바이트(Byte) 단위로 크기를 지정합니다.

# /etc/apache2/apache2.conf 또는 /etc/httpd/conf/httpd.conf

# 50MB = 52,428,800 Bytes
<Directory "/var/www/html/uploads">
    LimitRequestBody 52428800
</Directory>

# 특정 가상 호스트 전체 적용 시
<VirtualHost *:443>
    ServerName example.com
    LimitRequestBody 52428800
</VirtualHost>
  • 수정 후 반영:
    sudo apachectl configtest && sudo systemctl reload apache2
    

3) 백엔드 파이프라인 동기화 (PHP-FPM / Spring Boot)

웹 서버를 통과한 패킷이 백엔드에서 다시 거부당하지 않도록 일관성 있게 값을 맞춰야 합니다.

  • PHP (php.ini):
    upload_max_filesize = 50M
    post_max_size = 55M       ; post_max_size는 upload_max_filesize보다 커야 함
    memory_limit = 128M
    
  • Spring Boot (application.yml):
    spring:
      servlet:
        multipart:
          max-file-size: 50MB
          max-request-size: 55MB
    

   

주의사항

  1. 디스크 임시 버퍼 파티션 용량 부족 주의:
    • Nginx는 클라이언트 본문 크기가 client_body_buffer_size(보통 8KB~16KB)를 초과하면 본문을 메모리가 아닌 /var/lib/nginx/body/ 경로의 디스크 임시 파일에 기록합니다. 이때 해당 파티션의 디스크 공간이 부족하면 413 대신 500 내부 서버 오류가 발생하므로 디스크 용량을 사전 확인해야 합니다.
  2. 클라우드 로드밸런서(AWS ALB, Cloudflare 등)의 페이로드 제한 체인:
    • 웹 서버의 client_max_body_size를 500MB로 늘렸더라도 앞단 CDN/WAF(예: Cloudflare 무료 플랜은 100MB 제한, AWS API Gateway는 10MB 제한)에 의해 앞단에서 먼저 413이 반환될 수 있습니다. 인프라 전체 경로의 페이로드 제한을 함께 점검해야 합니다.
  3. 무차별 대용량 허용에 따른 DoS 공격 위험:
    • client_max_body_size 0;으로 완전 해제하거나 수 GB 단위로 전역 오픈할 경우, 악의적인 공격자가 기가바이트 단위의 더미 바이트 스트림을 전송하여 웹 서버의 디스크 I/O와 네트워크 대역폭을 고갈시킬 수 있습니다. 서비스 요구사항에 부합하는 최소한의 한도로 명시해야 합니다.