Skip to content

Large uploads and long requests: 413/504 across IIS, Nginx and the app

Verified 1 min read

Size body limits, timeouts and buffering at every hop, and choose streaming over a 30-minute HTTP request.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Task

A large upload crosses several limits:

Hop Limit
Browser/app its own max body
IIS maxAllowedContentLength (bytes)
Nginx client_max_body_size
Proxy ARR/proxy body limit
App framework body limit
Time HTTP.sys requestTimeout, Nginx client_body_timeout, proxy read timeout

Raise the smallest one first; do not set everything to unlimited.

<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="524288000" />
</requestFiltering>
</security>
</system.webServer>

524288000 = 500MB. Also check the handler/app limit (ASP.NET maxRequestLength, ANCM request body limit) and serverRuntime requestTimeout.

For uploads, uploadReadAheadSize can matter with client certificates/large headers; do not raise it blindly.

client_max_body_size 500m;
client_body_timeout 300s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;

client_body_temp_path needs disk space. For large streaming uploads, proxy_request_buffering off forwards bytes to the app instead of buffering the whole body on disk (tradeoff: the app must handle slow clients).

Set the framework’s limit too:

  • ASP.NET Core: RequestSizeLimit/Kestrel MaxRequestBodySize;
  • Express: express.json({ limit: '...' }) / multer limits;
  • Flask: MAX_CONTENT_LENGTH;
  • Tomcat: maxPostSize/connector limits.

If the app limit is lower, the proxy passes the body and the app rejects it (often a 413 from the app).

A 2GB upload or a 30-minute export should not be a single synchronous HTTP request:

  • direct-to-object-storage presigned upload;
  • chunked/resumable upload;
  • background job + status endpoint for exports;
  • download via signed URL/stream with a bounded timeout.
Terminal window
curl.exe -I -H "Content-Length: 600000000" https://lab.example/upload
curl.exe --limit-rate 100k -T big.bin https://lab.example/upload

Check the status at each hop and the IIS/Nginx logs. 413 is a body limit; 504 is a timeout; 502 is the upstream.

E1. The lab did not push a large upload through IIS/Nginx; the limits are the cross-hop checklist for Server 2025.

Sources