How to Handle Large File Uploads in Nginx: Redirect Users to Custom Error Page When Exceeding Size Limit


18 views

When building web applications that accept file uploads, handling oversized uploads gracefully becomes critical. While most developers know about the max-request-size configuration, the default behavior of returning a static error page often doesn't meet modern UX requirements.

Since you're using Nginx as a front-end, we can leverage its powerful rewrite capabilities to implement this properly:


# nginx.conf
http {
    client_max_body_size 10m;  # Set your desired limit
    
    server {
        error_page 413 /custom_413.html;
        location = /custom_413.html {
            root /var/www/error_pages;
            internal;
        }

        location /upload {
            if ($request_method = POST) {
                # Additional validation if needed
            }
            proxy_pass http://backend;
        }
    }
}

For more sophisticated handling, you can use Nginx's rewrite module:


map $content_length $upload_too_large {
    default 0;
    "~^[1-9][0-9]{7,}$" 1;  # Matches content-length over 10MB
}

server {
    if ($upload_too_large) {
        rewrite ^ /file-too-big last;
    }
    
    location /file-too-big {
        # Your custom error handling logic
        return 413;
    }
}

For complete control, combine Nginx with backend validation:


// Express.js middleware example
app.post('/upload', (req, res, next) => {
    const contentLength = req.headers['content-length'];
    if (contentLength > MAX_UPLOAD_SIZE) {
        return res.redirect('/file-too-big');
    }
    next();
});
  • Set appropriate client_max_body_size in both Nginx and your backend server
  • Handle chunked uploads differently as they won't have Content-Length header
  • Consider using JavaScript validation before upload begins
  • Provide clear error messages about size limits

When dealing with file uploads in web applications, we often need to enforce size limits. The standard approach of returning a generic 413 error page is insufficient for modern UX requirements. Here's how to implement custom redirection when uploads exceed specified limits.

The most efficient solution involves Nginx's client_max_body_size directive combined with error page handling. Here's a production-tested configuration:


http {
    # Set maximum body size (e.g., 10MB)
    client_max_body_size 10m;
    
    # Custom error handling
    error_page 413 /upload_too_large.html;
    
    server {
        listen 80;
        server_name example.com;
        
        location /upload {
            # Process uploads normally if within size limit
            proxy_pass http://backend;
            
            # Custom error handling for this specific location
            error_page 413 /custom_upload_error;
        }
        
        location = /custom_upload_error {
            internal;
            return 302 /file_too_large?size=$request_length;
        }
    }
}

For more granular control, we can implement size checking before the upload begins:


// Client-side JavaScript example
document.getElementById('uploadForm').addEventListener('submit', function(e) {
    const fileInput = document.getElementById('fileInput');
    const maxSize = 10 * 1024 * 1024; // 10MB
    
    if (fileInput.files[0].size > maxSize) {
        e.preventDefault();
        window.location.href = '/file_too_large?size=' + fileInput.files[0].size;
    }
});

Even with frontend checks, always validate server-side. Here's a Node.js example:


app.post('/upload', (req, res, next) => {
    const contentLength = parseInt(req.headers['content-length']);
    const maxSize = 10 * 1024 * 1024; // 10MB
    
    if (contentLength > maxSize) {
        return res.redirect('/file_too_large?size=' + contentLength);
    }
    
    // Continue with normal upload processing
    // ...
});

The complete flow should handle cases where the client doesn't cooperate with pre-validation:

  1. Client-side pre-check (JavaScript)
  2. Nginx size limitation
  3. Application-level validation
  4. Custom error page with helpful information
  • Set reasonable timeout values (client_body_timeout)
  • Log large file attempts for security monitoring
  • Provide clear error messages with size limits
  • Consider implementing progressive uploads for better UX