Docs / Web Servers / Handle Large File Uploads with Nginx

Handle Large File Uploads with Nginx

By Admin · Mar 15, 2026 · Updated Apr 24, 2026 · 350 views · 3 min read

Handling large file uploads (100MB+) with Nginx requires configuration changes at multiple levels — Nginx, your application framework, and potentially PHP-FPM. Misconfigurations cause frustrating "413 Request Entity Too Large" errors or timeouts during uploads. This guide covers configuring Nginx for reliable large file uploads.

Nginx Configuration

# /etc/nginx/nginx.conf or site config
http {
    # Maximum upload size (default: 1M)
    client_max_body_size 500M;

    # Buffer settings for large uploads
    client_body_buffer_size 128k;
    client_body_temp_path /var/cache/nginx/uploads 1 2;

    # Timeout settings (large files take time)
    client_body_timeout 300s;
    send_timeout 300s;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    proxy_connect_timeout 60s;

    server {
        listen 443 ssl http2;

        # Per-location override
        location /upload {
            client_max_body_size 2G;  # 2GB limit for this endpoint
            client_body_buffer_size 256k;
            client_body_timeout 600s;

            proxy_pass http://127.0.0.1:8080;
            proxy_request_buffering off;  # Stream directly to backend
            proxy_http_version 1.1;
            proxy_set_header Connection "";
        }

        # Regular locations use the default 500M limit
        location / {
            proxy_pass http://127.0.0.1:8080;
        }
    }
}

Streaming Uploads (Proxy Buffering Off)

# For very large files, disable request buffering
# Nginx will stream the body directly to the backend
# instead of buffering it to disk first

location /upload {
    proxy_pass http://127.0.0.1:8080;
    proxy_request_buffering off;  # Don't buffer to disk

    # The backend receives data as it arrives
    # Reduces disk I/O and latency for large uploads

    # Still need adequate timeouts
    proxy_read_timeout 600s;
    client_body_timeout 600s;
}

PHP-FPM Configuration

# php.ini settings for large uploads
upload_max_filesize = 500M
post_max_size = 512M        # Must be slightly larger than upload_max_filesize
memory_limit = 768M         # Must be larger than post_max_size
max_execution_time = 300
max_input_time = 300

# PHP-FPM pool settings
request_terminate_timeout = 300

# Restart PHP-FPM
sudo systemctl restart php8.3-fpm

Chunked Upload for Very Large Files

# For files over 1GB, implement chunked uploads in your application
# Frontend sends file in chunks; backend reassembles

# Nginx config for chunked uploads
location /upload/chunk {
    client_max_body_size 50M;  # Each chunk is small
    client_body_buffer_size 50M;

    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Content-Range $http_content_range;
    proxy_set_header X-Upload-ID $arg_upload_id;
}

# JavaScript example (using tus or custom chunking):
# const CHUNK_SIZE = 10 * 1024 * 1024; // 10MB chunks
# for (let offset = 0; offset < file.size; offset += CHUNK_SIZE) {
#     const chunk = file.slice(offset, offset + CHUNK_SIZE);
#     await fetch('/upload/chunk?upload_id=' + uploadId, {
#         method: 'POST',
#         headers: { 'Content-Range': `bytes ${offset}-${offset+chunk.size-1}/${file.size}` },
#         body: chunk
#     });
# }

Upload Progress Tracking

# Nginx upload progress module (nginx-upload-progress-module)
# Or use the Nginx Upload Module for direct file handling

# Alternative: Use application-level progress
# The backend can track upload progress and expose it via API

# WebSocket-based progress
location /upload/progress {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Disk Space and Temp Files

# Nginx buffers uploads to disk in client_body_temp_path
# Ensure adequate disk space and permissions

# Check temp directory
ls -la /var/cache/nginx/uploads/

# Create with correct permissions
sudo mkdir -p /var/cache/nginx/uploads
sudo chown www-data:www-data /var/cache/nginx/uploads

# Monitor disk during uploads
df -h /var/cache/nginx/

# Clean up stale temp files
find /var/cache/nginx/uploads -type f -mtime +1 -delete

Best Practices

  • Set client_max_body_size at the location level for upload endpoints — don't set it globally to 2G
  • Use proxy_request_buffering off for large files to avoid disk buffering
  • Implement chunked uploads for files over 1GB for reliability and resumability
  • Match timeouts: Nginx, PHP-FPM, and your app framework all need adequate timeout values
  • Monitor temp disk usage during high-volume upload periods
  • Set PHP post_max_size slightly larger than upload_max_filesize

Was this article helpful?