devkult_
tools29converters34
home/blog/nginx-413-request-entity-too-large
nginxhttpuploads

413 Request Entity Too Large in nginx: How to Raise the Upload Limit

413 Request Entity Too Large
nginx

The server refused the request because its body — usually a file upload — is bigger than it allows. HTTP now calls this status 413 Content Too Large; nginx still prints the old name. nginx's default limit is just 1 MB, so the first large upload on a new server almost always hits it.

Raise the limit in nginx

client_max_body_size can go in the http, server or location block:

server {
    # ...
    client_max_body_size 50m;

    location /api/upload {
        client_max_body_size 500m;  # larger limit for one endpoint
    }
}

Then test the config and reload:

sudo nginx -t && sudo systemctl reload nginx

client_max_body_size 0; disables the check entirely — better to set a real ceiling. nginx checks the request's Content-Length up front, so an oversized upload is rejected before it's transferred.

Then check every other layer

Each layer in front of your code has its own limit, and the smallest one wins. If the 413 persists after changing nginx, look at the response body and headers to see which layer sent it.

PHP — two settings in php.ini, then restart PHP-FPM:

upload_max_filesize = 50M
post_max_size = 50M

The defaults are 2M and 8M. post_max_size must be at least as large as upload_max_filesize.

Express — body parsers default to 100 KB and answer with PayloadTooLargeError: request entity too large:

app.use(express.json({ limit: "10mb" }));
app.use(express.urlencoded({ extended: true, limit: "10mb" }));

For file uploads, use a streaming parser such as multer or busboy and set its limits instead.

Next.js — Server Actions accept 1 MB by default; raise it in next.config.js:

module.exports = {
  experimental: {
    serverActions: { bodySizeLimit: "10mb" },
  },
};

In the Pages Router, API routes have their own 1 MB default, set per route with export const config = { api: { bodyParser: { sizeLimit: "10mb" } } }. And if requests pass through middleware (proxy.ts in Next.js 16), their bodies are capped at 10 MB unless you raise experimental.proxyClientMaxBodySize.

Kubernetes ingress-nginx — set it per Ingress with an annotation:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"

Hosting platforms and CDNs have fixed ceilings you can't raise in config: Vercel Functions accept request bodies up to 4.5 MB, AWS API Gateway up to 10 MB, and Cloudflare's limit depends on your plan (100 MB on Free and Pro).

For really large files, skip your server

Uploading big files through your app server ties up a worker for the whole transfer and runs into every limit above. Instead, have your server issue a presigned upload URL for S3, R2, GCS or similar, and let the browser upload straight to storage. Your server only handles a small JSON request, and the size limit becomes the storage provider's (gigabytes).

Show a useful error

Check file sizes in the browser before uploading, so users don't wait for a 413:

const MAX = 50 * 1024 * 1024;
if (file.size > MAX) {
  alert(`That file is ${(file.size / 1024 / 1024).toFixed(1)} MB; the limit is 50 MB.`);
}

Hit a 502 instead after raising limits? Large uploads can also time out between nginx and your app — see how to fix 502 Bad Gateway in nginx.

More from the blog