httpd 앞단을 거쳐 파일을 올릴 때 413 Request Entity Too Large 가 나면 원인은 대개 한 곳이 아니다. httpd 자체의 요청 본문 상한, 그 뒤에 붙은 애플리케이션(PHP · WSGI · Hue 등)의 상한, 그리고 전송 시간 상한이 각각 따로 걸려 있고 그중 가장 작은 값이 실제 한계가 된다. 세 가지를 같은 기준으로 맞춰야 한다.
LimitRequestBody 는 요청 본문의 최대 바이트 수를 정한다. 기본값은 0 이며 이는 무제한을 뜻한다. 서버 전체 · 가상호스트 · <Directory> · <Location> · .htaccess 어디에나 둘 수 있고, 좁은 범위의 설정이 넓은 범위를 덮는다.
<Directory "/var/www/html/upload">
LimitRequestBody 52428800
</Directory>
값은 바이트 단위다. 위 예시의 52428800 은 50MiB 다. 단위 접미사(50M 같은 표기)는 받지 않으므로 반드시 숫자로 적는다.
상한을 넘기면 httpd 가 413 을 돌려주고 요청 본문은 애플리케이션까지 가지 않는다. 즉 애플리케이션 로그에는 아무 흔적이 남지 않으므로, 애플리케이션 쪽만 보다가 원인을 놓치기 쉽다.
httpd 를 통과해도 애플리케이션이 다시 막는다. 대표적인 것들은 다음과 같다.
| 대상 | 설정 | 위치 |
|---|---|---|
| PHP | upload_max_filesize, post_max_size, memory_limit |
php.ini |
| Hue | max_file_size |
hue.ini 의 [desktop] 절 |
| mod_wsgi 애플리케이션 | 프레임워크별 업로드 상한 | 애플리케이션 설정 |
[desktop]
max_file_size=52428800
PHP 는 post_max_size 가 upload_max_filesize 보다 커야 한다. 전자가 작으면 파일 자체는 통과해도 POST 본문 전체가 잘려 업로드가 실패한다.
크기 제한을 풀어도 회선이 느리면 전송 도중 연결이 끊긴다. 이때는 413 이 아니라 타임아웃이나 빈 응답이 나온다.
Timeout 600
리버스 프록시를 거친다면 프록시 쪽 타임아웃도 같이 늘려야 한다. mod_proxy 를 쓰면 ProxyTimeout, nginx 를 앞에 두면 proxy_read_timeout 과 client_max_body_size 가 대응한다.
설정 파일을 고친 뒤에는 문법을 먼저 확인하고 재적재한다.
httpd -t
systemctl reload httpd
실제로 걸리는 값을 확인하려면 상한보다 조금 큰 파일로 올려 보고 응답 코드를 본다.
curl -o /dev/null -w '%{http_code}\n' -F file=@big.bin https://example.com/upload
413 이 나오면 httpd 단계에서 막힌 것이고, 200 계열인데 애플리케이션이 실패를 알리면 애플리케이션 상한이다.
LimitRequestBody 는 .htaccess 에서도 먹지만, 그러려면 해당 디렉터리에 AllowOverride Limit 이상이 필요하다.