How to Disable HTTP 206 Partial Content in Nginx for Full Video Downloads


2 views

When serving video files through Nginx, the server typically responds with HTTP 206 Partial Content to support byte-range requests. While this is great for streaming scenarios, it becomes problematic when you need the browser to download the entire file upfront.


location ~* \.(mp4|webm)$ {
    max_ranges 0;
    add_header Accept-Ranges none;
    add_header Content-Length $content_length;
}

The key directives here are:

  • max_ranges 0 - Explicitly disables range requests
  • Accept-Ranges none - Tells clients range requests aren't supported
  • Content-Length - Ensures browsers know the full size upfront

After implementing this, you can verify it's working with curl:


curl -I http://yourserver.com/video.mp4

You should see:


HTTP/1.1 200 OK
Accept-Ranges: none
Content-Length: 5242880

If modifying Nginx isn't an option, you can force full downloads through JavaScript:


// Pre-load the entire video
const video = document.createElement('video');
video.preload = 'auto';
video.src = 'video.mp4';

// Or using fetch API
fetch('video.mp4')
  .then(response => response.blob())
  .then(blob => {
    const video = document.querySelector('video');
    video.src = URL.createObjectURL(blob);
  });

Only disable range requests for small videos (under 5MB as mentioned). For larger files, consider:

  • Implementing a hybrid solution where initial segments are forced
  • Using service workers to cache the entire video after first load
  • Compressing videos to reduce initial load time

When working with HTML5 video elements in web applications, browsers typically make HTTP range requests (using the Range header) to fetch specific portions of media files. While this behavior is excellent for optimizing bandwidth usage in streaming scenarios, it becomes problematic when you need to ensure the entire video is downloaded upfront.

In my particular case with a 5MB video web app, I needed to guarantee complete video downloads because:

  • Users might jump to different video segments unpredictably
  • Buffering delays occurred when accessing later portions of the video
  • The small file size made full downloads preferable to partial requests

The most straightforward approach is to modify your nginx configuration to ignore range requests:


location ~* \.(mp4|webm|ogg)$ {
    # Disable range requests
    max_ranges 0;
    
    # Force complete file download
    add_header Accept-Ranges none;
    
    # Optional: Set appropriate MIME types
    types {
        video/mp4 mp4;
        video/webm webm;
        video/ogg ogv;
    }
}

For cases where you might need more control:


# Option 1: Remove Accept-Ranges header completely
location /videos/ {
    add_header Accept-Ranges "";
}

# Option 2: Conditional logic based on file size
map $request_uri $disable_ranges {
    default 1;
    ~*small-video\.mp4$ 0;
}

server {
    ...
    if ($disable_ranges) {
        add_header Accept-Ranges none;
    }
}

After implementing these changes, verify the behavior using curl:


curl -I http://yourserver.com/video.mp4

Look for these indicators of success:

  • No Accept-Ranges: bytes header in response
  • HTTP 200 status code instead of 206 for video requests

While this solution works for most modern browsers, remember that:

  • Some older browsers might still attempt range requests
  • Mobile browsers sometimes have different caching behaviors
  • The solution affects all matching files in the configured location

Before implementing this solution universally, consider:

  • For larger videos (>10MB), partial content might be preferable
  • You might want to implement different strategies for different video types
  • Monitor server load as complete downloads increase bandwidth usage