Nginx returns 413 Request Entity Too Large when an upload exceeds client_max_body_size — and the default is only 1 MB, small enough that one photo from a phone can trip it.
413 Request Entity Too Large
nginx/1.24.0
The matching line in /var/log/nginx/error.log:
client intended to send too large body: 4823910 bytes, client: 203.0.113.9,
server: example.com, request: "POST /upload HTTP/1.1"
That number is the size the client tried to send. Set your limit above it.
The Fix
Add client_max_body_size to your nginx config:
http {
client_max_body_size 50m;
...
}
Then test and reload:
sudo nginx -t
sudo systemctl reload nginx
Always run nginx -t first. If the config has a syntax error, reload fails and nginx quietly keeps serving the old config — so you would be testing a change that never applied.
Where to put it
The directive is valid in three contexts, and the choice matters:
| Context | Effect | When to use |
|---|---|---|
http | Every site on the server | Simple single-purpose servers |
server | One virtual host | One site needs larger uploads |
location | One path only | Safest — raise it just for the upload endpoint |
Scoping it to a location is the better habit:
server {
server_name example.com;
client_max_body_size 1m; # default for the whole site
location /api/upload {
client_max_body_size 200m; # only this endpoint accepts large files
proxy_pass http://127.0.0.1:3000;
}
}
That way an attacker cannot POST a 200 MB body to your login form.
Which file to edit
| Distribution | Main config | Site configs |
|---|---|---|
| Debian / Ubuntu | /etc/nginx/nginx.conf | /etc/nginx/sites-available/ |
| RHEL / Rocky / AlmaLinux | /etc/nginx/nginx.conf | /etc/nginx/conf.d/*.conf |
If you are unsure which files nginx actually loads, ask it:
sudo nginx -T | grep -n "client_max_body_size"
nginx -T dumps the fully resolved configuration including every include. If your directive does not appear there, nginx is not reading the file you edited — the single most common reason "I already set it" fails.
Still 413 After Raising the Limit?
Another proxy is enforcing a smaller limit
Every layer between the client and your application enforces its own maximum. Raising it on one does nothing if a stricter one sits in front:
browser → CDN → load balancer (nginx) → app server (nginx) → application
Each hop needs the higher limit. A CDN in front of you may cap uploads by plan tier regardless of your configuration — check your provider's limits before spending an hour on nginx.
PHP has its own limits
Nginx accepting the body does not mean PHP will. In php.ini:
upload_max_filesize = 50M
post_max_size = 55M
Set post_max_size slightly above upload_max_filesize, because the POST body includes form fields and multipart overhead in addition to the file itself. Both must be at least as large as the nginx limit. Then restart PHP-FPM — reloading nginx does nothing here:
sudo systemctl restart php8.3-fpm
php -i | grep -E "upload_max_filesize|post_max_size"
Kubernetes ingress-nginx
Do not edit nginx.conf inside the controller pod; it is regenerated and your change disappears. Use the annotation:
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
The application enforces its own cap
Express (body-parser limit), Django (DATA_UPLOAD_MAX_MEMORY_SIZE), Rails, and most upload libraries have independent limits. If nginx logs no error but the client still sees a rejection, the request reached your app and your app said no.
Related but Different: client_body_buffer_size
client_body_buffer_size 128k; # default 8k or 16k
This does not change what nginx accepts. It controls how much of the body is held in memory before nginx spills it to a temporary file on disk. Raising it can reduce disk I/O for moderately sized uploads, but it will never fix a 413 — and setting it very large multiplies memory use by the number of concurrent uploads.
Verify the Fix
Send a real file of a known size:
# make a 20 MB test file
dd if=/dev/zero of=/tmp/test.bin bs=1M count=20
curl -s -o /dev/null -w "%{http_code}\n" \
-F "file=@/tmp/test.bin" https://example.com/upload
A 200, 201, or 302 means the limit is doing what you want. A 413 means something in the chain is still capping you — check the error log to find out which nginx logged it:
sudo tail -f /var/log/nginx/error.log
If no client intended to send too large body line appears, nginx is not the layer rejecting the request. See Where Are Nginx Logs Stored? if the log is not in the default location.
Clean up the test file afterwards:
rm /tmp/test.bin
Prevention
- Set the limit deliberately when you build the server, not after the first user complains. The 1 MB default is a placeholder, not a recommendation.
- Scope generous limits to upload endpoints only. A site-wide 500 MB limit is an easy way for someone to exhaust your disk.
- Keep nginx and application limits in sync, and document the number somewhere both teams can see — mismatched limits produce a confusing failure where the upload appears to succeed and then fails.
- Return a useful error. A bare nginx 413 page tells users nothing; catch the size client-side and say what the maximum is before they wait through the upload.