← All articles

How to Fix 413 Request Entity Too Large in Nginx, PHP and Cloudflare

Fix HTTP 413 upload errors by aligning limits in Cloudflare, Nginx, PHP, and your application, then verify the effective configuration safely.

Bakry Abdalsalam builds websites, applications, integrations, and WordPress products. Bakry Dev Hub documents the technical decisions behind this work.

THE SHORT VERSION

An upload must fit through every layer. Find which layer returns 413, set the narrowest appropriate limit in Cloudflare, Nginx, PHP, and the application, then test just below and above the boundary.

An HTTP 413 Content Too Large response—historically called 413 Request Entity Too Large—means a request body exceeded a limit. On a typical PHP site, the request may pass through Cloudflare, Nginx, PHP-FPM, and application validation. The smallest effective limit wins.

Choose a business limit before editing configuration. A 25 MB media upload does not justify allowing multi-gigabyte request bodies across the whole site.

Identify the layer returning 413

Capture the response headers and inspect the Nginx logs while reproducing the upload:

curl -i -F "file=@sample.bin" https://example.com/upload
sudo tail -f /var/log/nginx/error.log

If Nginx rejects the body, its error log commonly records client intended to send too large body. If there is no corresponding Nginx access or error entry, an upstream proxy or CDN may have rejected the request first.

Test the origin directly only from an authorized network and with the correct Host header. Do not publish an unprotected origin IP merely to bypass a CDN.

Also distinguish an application validation response such as 422 from a true 413. Changing server limits will not override a framework rule that intentionally caps file size.

Set Nginx client_max_body_size

Nginx controls the accepted request body with client_max_body_size. Set it at the narrowest useful context:

server {
    server_name example.com;

    location /upload {
        client_max_body_size 25m;
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Placing the directive in http, server, or location changes its scope. A route-specific limit protects the rest of the application from unnecessarily large bodies.

Validate and reload:

sudo nginx -t
sudo systemctl reload nginx

If the response remains unchanged, inspect the active configuration—not only the file you expected Nginx to load:

sudo nginx -T | grep -n client_max_body_size

Align PHP upload limits

For PHP file uploads, review the loaded php.ini for the FPM service:

php --ini
php -i | grep -E 'upload_max_filesize|post_max_size|max_file_uploads'

The CLI can load a different configuration from PHP-FPM, so a small diagnostic page or php-fpm -i is more authoritative for web requests. Remove any diagnostic page immediately after use.

A 25 MB single-file policy could use:

upload_max_filesize = 25M
post_max_size = 28M
max_file_uploads = 10

post_max_size must be larger than upload_max_filesize because the entire multipart request includes form fields and encoding overhead. Restart PHP-FPM after changing the FPM configuration:

sudo systemctl restart php8.3-fpm

Do not automatically raise memory_limit to the upload size. PHP can stream uploaded files to temporary storage, but image processing or reading the complete file into memory may require much more memory. Measure the actual application behavior.

Check Cloudflare’s plan limit

When traffic is proxied through Cloudflare, the request must also fit its maximum request-body size. As of July 2026, Cloudflare documents 100 MB for Free and Pro plans, 200 MB for Business, and 500 MB by default for Enterprise. Verify the current Cloudflare request-size limits before relying on those values.

If the required object is larger than the edge limit, changing Nginx or PHP cannot help because the request never reaches them. Better patterns include:

  • Browser-to-object-storage uploads using short-lived signed URLs.
  • Multipart or resumable uploads.
  • A separate, authenticated upload host that is not proxied, with strict firewall and rate controls.
  • Client-side validation that explains the limit before transferring the file.

Do not disable proxy protection for the entire site to accommodate one upload endpoint.

Keep application validation explicit

The server limit is a transport ceiling, not a product rule. Validate the file’s size, type, content, and authorization in the application. Use a lower application limit when different account types have different allowances.

Reject invalid files before expensive transformations. Generate server-side filenames, store uploads outside executable web paths, and scan untrusted files where the risk model requires it.

For Laravel, remember that file-size validation rules and web-server units may differ. Test the exact boundary instead of assuming 25m in Nginx equals every framework value.

Verify every boundary

Create safe test files without sensitive data:

truncate -s 24M below-limit.bin
truncate -s 26M above-limit.bin

curl -o /dev/null -sS -w '%{http_code}\n' \
  -F "file=@below-limit.bin" https://example.com/upload

curl -o /dev/null -sS -w '%{http_code}\n' \
  -F "file=@above-limit.bin" https://example.com/upload

Confirm that:

  1. A file just below the product limit succeeds.
  2. A file just above it receives a controlled client error.
  3. Nginx, PHP, and the application agree on the intended boundary.
  4. Temporary disk space remains healthy during concurrent uploads.
  5. Upload failures do not leave orphaned partial objects.

Common mistakes and prevention

Frequent causes of a stubborn 413 include editing the CLI php.ini instead of FPM’s, putting client_max_body_size in an inactive server block, forgetting to reload Nginx, setting post_max_size smaller than the file limit, or overlooking a CDN limit.

Document the effective limits beside the upload feature, exercise them in release tests, and monitor rejected body sizes without logging file contents. For other upstream boundary failures, use the 502 Bad Gateway troubleshooting guide and the Nginx production checklist.

Frequently asked questions

Why is PHP’s upload array empty after a large POST?

When the complete request exceeds post_max_size, PHP can reject it before normal file handling, leaving the expected form data empty. Check the FPM configuration and request size together.

Can an Nginx change bypass Cloudflare’s upload limit?

No. If Cloudflare rejects the request, it never reaches Nginx. Use a supported plan limit or a direct signed upload flow for larger objects.

Official references

Have a question about this guide or an idea for a technical collaboration? Contact Bakry through the Dev Hub.

End of field note.