Uploading a 500 MB video or a large backup through a web app often fails with 413 Request Entity Too Large, a timeout, or a silent error. Each layer between the browser and your code has its own limit: the CDN, Nginx, PHP or Node, and the application. Here’s how to raise them safely, and when to use better upload methods.

The layers and their limits

Layer Setting Default
Cloudflare (proxied) Request body limit by plan 100 MB on Free/Pro
Nginx client_max_body_size 1 MB
Nginx → app proxy_read_timeout, client_body_timeout 60 s
PHP upload_max_filesize, post_max_size, max_execution_time, max_input_time 2 MB / 8 MB
Node/Express body parser limits (express.json({limit}), multer limits) ~100 KB (JSON)
App/framework Validation rules App-specific

The smallest limit wins.

Nginx

server {
    # …
    client_max_body_size 1G;          # per server or per location
    client_body_timeout 300s;
    proxy_read_timeout 300s;          # when proxying to an app
    proxy_send_timeout 300s;

    location /upload {
        proxy_request_buffering off;  # stream to the app instead of buffering to disk first
        proxy_pass http://127.0.0.1:3000;
    }
}

By default Nginx buffers the whole upload to a temp file before passing it on. That’s fine, but it needs disk space in client_body_temp_path. See Nginx 413 errors and Nginx 504 timeouts.

PHP

; /etc/php/8.3/fpm/conf.d/99-uploads.ini
upload_max_filesize = 1G
post_max_size = 1G            ; must be >= upload_max_filesize
max_execution_time = 300
max_input_time = 300
memory_limit = 256M           ; uploads stream to disk; memory needn't match file size
sudo systemctl reload php8.3-fpm

WordPress has its own guide: increase the WordPress upload size. See php.ini settings.

Node.js

Stream uploads to disk or object storage, instead of loading them into memory:

import multer from "multer";
const upload = multer({ dest: "/var/uploads/tmp", limits: { fileSize: 1024 * 1024 * 1024 } });
app.post("/upload", upload.single("file"), (req, res) => res.json({ ok: true, size: req.file.size }));

busboy (lower level), or streaming directly to S3 with @aws-sdk/lib-storage, avoids memory spikes.

Better: resumable or chunked uploads

Huge single requests fail on flaky connections, and hit proxy limits. Chunked, resumable uploads split files into pieces, and resume after interruptions:

  • tus protocol (tusd server, Uppy client): widely used, open standard.
  • Framework packages (Laravel chunk upload, Resumable.js and others).

Chunks also stay under Cloudflare’s per-request limit.

Best for very large files: direct-to-object-storage

Have the browser upload directly to S3-compatible storage (MinIO, AWS S3, Backblaze B2) with a presigned URL generated by your app:

  1. The client asks your API for an upload URL.
  2. The API returns a short-lived presigned PUT URL (or multipart upload URLs).
  3. The browser uploads straight to storage. Your VPS never carries the bytes.
  4. The client tells your API the upload finished. The API verifies it, and records it.

That saves bandwidth, disk space and app workers. See MinIO.

Security for uploads

  • Validate type and size server-side (check content, not just the extension).
  • Store uploads outside the web root, or in a location where scripts can’t execute. Block PHP in upload directories. See the ideal Nginx config for WordPress.
  • Generate your own file names. Never trust user-supplied paths.
  • Scan uploads if users share files with others (ClamAV).
  • Rate-limit upload endpoints, and require authentication.

Disk and bandwidth planning

Large uploads fill disks quickly: temp files, the uploads themselves, and backups of them. Monitor free space, and consider a storage VPS or object storage for user files. See VPS storage planning and storage VPS.

Quick reference

Layer Key setting
Nginx client_max_body_size, timeouts, proxy_request_buffering off
PHP upload_max_filesize, post_max_size, time limits
Node multer/busboy limits; stream, don’t buffer
Cloudflare Per-request limit → chunking or bypass
Huge files tus resumable uploads, or presigned S3 uploads

Related: Nginx reverse proxy and Express security.

  • Nginx
  • Web Development
  • Performance