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


2 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