# Fix Nginx 413 Request Entity Too Large for File Uploads
A user tries to upload a 25MB video to your application and gets an immediate 413 error. The Nginx error log confirms:
2026/04/08 16:05:11 [error] 4521#4521: *12345 client intended to send too large body: 26214400 bytes, client: 203.0.113.15, server: app.example.com, request: "POST /api/uploads/video HTTP/1.1", host: "app.example.com"Nginx rejects the request before it ever reaches your application. The default client_max_body_size is 1MB, and any request with a Content-Length header exceeding this limit receives a 413 response immediately.
The Quick Fix
In your Nginx server block or location block:
```nginx server { client_max_body_size 100m;
location /api/uploads/ { client_max_body_size 500m; proxy_pass http://127.0.0.1:3000; } } ```
The client_max_body_size directive can be set at the http, server, or location level. Setting it in a location block allows different limits for different endpoints.
The Complete Upload Configuration
Simply raising the limit is not enough for production. Large uploads need additional tuning:
```nginx server { client_max_body_size 500m;
location /api/uploads/ { client_max_body_size 500m; proxy_read_timeout 300s; proxy_send_timeout 300s; proxy_connect_timeout 30s; proxy_request_buffering on; proxy_buffering on; proxy_buffer_size 128k; proxy_buffers 8 256k; proxy_pass http://127.0.0.1:3000; }
location /api/uploads/stream/ { client_max_body_size 2048m; proxy_request_buffering off; proxy_buffering off; proxy_read_timeout 600s; proxy_pass http://127.0.0.1:3000; } } ```
Understanding Body Size Checking
Nginx checks the body size in two ways. If the Content-Length header is present, Nginx checks immediately and returns 413 if the value exceeds client_max_body_size. If there is no Content-Length (chunked encoding), Nginx reads the body and tracks the accumulated size, returning 413 when the limit is exceeded during reading.
This means you cannot bypass the limit by using chunked transfer encoding -- Nginx still enforces it.
Common Pitfall: PHP Upload Limits
Even after configuring Nginx, PHP has its own limits. Check /etc/php/8.2/fpm/php.ini:
upload_max_filesize = 500M
post_max_size = 510M
max_input_time = 300
max_execution_time = 300Note that post_max_size must be larger than upload_max_filesize because it includes all POST data, not just the file. The max_input_time controls how long PHP spends reading input data.
Common Pitfall: Node.js Body Parser
If your backend is Node.js with Express, the body-parser middleware also has limits:
```javascript const express = require('express'); const app = express();
app.use(express.json({ limit: '500mb' })); app.use(express.urlencoded({ extended: true, limit: '500mb' })); app.use(express.raw({ limit: '500mb' })); ```
Monitoring Upload Sizes
Add logging to track upload patterns:
```nginx log_format upload_log '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'body_size=$request_length time=$request_time';
access_log /var/log/nginx/upload-access.log upload_log; ```
The $request_length variable includes the request line, headers, and body. This lets you analyze actual upload sizes and tune client_max_body_size appropriately.
Testing the Configuration
dd if=/dev/zero of=/tmp/test-upload.bin bs=1M count=100
curl -v -X POST -F "file=@/tmp/test-upload.bin" https://app.example.com/api/uploads/ -w "\nHTTP Code: %{http_code}\n"If you get a 200, the upload succeeded. If you still get 413, check that the directive is in the correct server or location block, Nginx was reloaded after the change, and no other location block with a lower limit is matching the request.
Memory Considerations
When proxy_request_buffering on (the default), Nginx buffers the entire request body to disk before sending it upstream. The buffer directory is controlled by client_body_temp_path:
client_body_temp_path /tmp/nginx-body 1 2;Ensure this directory has enough disk space for concurrent uploads. If 10 users simultaneously upload 500MB files, you need at least 5GB of free space in the temp path. Use a tmpfs mount for faster I/O:
sudo mount -t tmpfs -o size=2g tmpfs /tmp/nginx-body