Skip to main content

NGINX

NGINX VOD Module: Advanced Video Streaming Configuration

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

The NGINX VOD module transforms your web server into a powerful video-on-demand platform. Developed by Kaltura, this module repackages MP4 files on-the-fly to HLS, DASH, HDS, and MSS formats. No pre-processing or transcoding is required. System administrators will find it eliminates the complexity of maintaining multiple video formats.

Traditional streaming solutions require pre-packaged content in every format. The NGINX VOD module takes a different approach. It reads a single MP4 file and generates manifests dynamically. This simplifies content management and enables instant video availability.

Key Features

This module provides enterprise-grade video streaming capabilities:

  • Multi-Protocol Support: HLS (Apple), DASH (MPEG), HDS (Adobe), and MSS (Microsoft Smooth Streaming)
  • Working Modes: Local files, remote HTTP, or mapped JSON configurations
  • Adaptive Bitrate: Multi-bitrate streaming with automatic manifest generation
  • DRM Integration: CENC encryption for DASH, PlayReady for MSS, FairPlay and AES-128 for HLS
  • Live Simulation: Generate live streams from VOD content for testing
  • Thumbnail Generation: Extract thumbnails at any timestamp (requires ffmpeg)
  • Content Clipping: Serve portions of videos without re-encoding

Installing the NGINX VOD Module

RHEL, CentOS, AlmaLinux, Rocky Linux

Install from the GetPageSpeed repository:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-vod

Enable it by adding to /etc/nginx/nginx.conf:

load_module modules/ngx_http_vod_module.so;

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install:

sudo apt-get update
sudo apt-get install nginx-module-vod

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

Verify it loads correctly:

nginx -t

Basic Configuration for HLS Streaming

Minimal configuration is needed for HLS. Here is a complete working example:

# Define caches in http context
vod_metadata_cache metadata_cache 512m;
vod_response_cache response_cache 128m;
vod_performance_counters vod_pc;

server {
    listen 80;
    server_name streaming.example.com;

    # HLS streaming location
    location /hls/ {
        alias /var/www/videos/;
        vod hls;
        vod_mode local;
        vod_segment_duration 10000;
        vod_align_segments_to_key_frames on;

        add_header Access-Control-Allow-Origin "*";
        add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";

        expires 1d;
    }
}

Place MP4 files in /var/www/videos/ and access them via URLs like:

  • Master playlist: `http://streaming.example.com/hls/video.mp4/master.m3u8`
  • Media playlist: `http://streaming.example.com/hls/video.mp4/index-v1-a1.m3u8`

DASH Streaming Configuration

MPEG-DASH provides better cross-platform compatibility for non-Apple devices:

location /dash/ {
    alias /var/www/videos/;
    vod dash;
    vod_mode local;
    vod_segment_duration 10000;
    vod_align_segments_to_key_frames on;

    # DASH-specific options
    vod_dash_manifest_format segmenttimeline;
    vod_dash_profiles "urn:mpeg:dash:profile:isoff-main:2011";

    add_header Access-Control-Allow-Origin "*";
    expires 1d;
}

Access DASH content via `http://streaming.example.com/dash/video.mp4/manifest.mpd`.

Advanced Cache Configuration

Proper caching dramatically improves performance. Multiple cache types are supported:

# Metadata cache - stores MP4 moov atom data
# Allocate generously as this cache has the highest impact
vod_metadata_cache metadata_cache 1g 30d;

# Response cache - stores manifest responses
vod_response_cache response_cache 128m 1d;

# Live response cache - for time-varying live responses
vod_live_response_cache live_cache 64m 5m;

# Mapping cache - for mapped mode only
vod_mapping_cache mapping_cache 16m 30m;

The format is cache_name size [expiration]. Size uses standard nginx notation (k/m/g).

Bootstrap Segments for Faster Playback

Bootstrap segments allow players to select the optimal bitrate faster:

location /hls/ {
    alias /var/www/videos/;
    vod hls;
    vod_mode local;

    # First 3 segments are shorter (2s, 2s, 4s) then switch to 10s
    vod_segment_duration 10000;
    vod_bootstrap_segment_durations 2000;
    vod_bootstrap_segment_durations 2000;
    vod_bootstrap_segment_durations 4000;

    vod_align_segments_to_key_frames on;
}

This reduces initial buffering time. Efficiency is maintained for the rest of playback.

HLS Encryption with AES-128

Protect video content with AES-128 encryption:

location /hls-secure/ {
    alias /var/www/videos/;
    vod hls;
    vod_mode local;
    vod_segment_duration 10000;

    # Enable AES-128 encryption
    vod_hls_encryption_method aes-128;
    vod_secret_key "your_secret_prefix_$vod_filepath";

    add_header Access-Control-Allow-Origin "*";
}

The encryption key is generated automatically. It is served at the .../encryption.key path. For production, protect the key endpoint with authentication.

For SAMPLE-AES encryption (required for certain devices):

vod_hls_encryption_method sample-aes;

DRM Configuration for Enterprise Deployments

Industry-standard DRM systems are supported for DASH and HLS.

Widevine/PlayReady (DASH CENC)

location /drm-dash/ {
    alias /var/www/videos/;
    vod dash;
    vod_mode local;

    vod_drm_enabled on;
    vod_drm_upstream_location /drm-server;
    vod_drm_request_uri "/get-keys?file=$vod_filepath";
    vod_drm_info_cache drm_cache 64m 1h;
}

location /drm-server {
    internal;
    proxy_pass http://your-drm-server:8080;
}

FairPlay (HLS)

location /fairplay/ {
    alias /var/www/videos/;
    vod hls;
    vod_mode local;

    vod_hls_encryption_method sample-aes;
    vod_hls_encryption_key_uri "skd://license-server/key";
    vod_hls_encryption_key_format "com.apple.streamingkeydelivery";
    vod_hls_encryption_key_format_versions "1";

    vod_drm_enabled on;
    vod_drm_upstream_location /drm-server;
}

Mapped Mode for Dynamic Content

Mapped mode fetches content paths from an upstream server or local JSON:

location /vod/ {
    vod hls;
    vod_mode mapped;
    vod_upstream_location /api;
    vod_mapping_cache mapping_cache 16m 30m;
}

location /api {
    internal;
    proxy_pass http://content-api:8080/media/;
}

The upstream server returns JSON describing the video sources:

{
    "sequences": [
        {
            "clips": [
                {
                    "type": "source",
                    "path": "/storage/videos/video1_720p.mp4"
                }
            ]
        }
    ]
}

This enables adaptive bitrate sets, playlists, and complex content assembly.

URL Parameters for Content Manipulation

URL path parameters enable content manipulation without re-encoding.

Clipping

Extract a portion of a video:

/hls/video.mp4/clipFrom/30000/clipTo/90000/master.m3u8

This serves seconds 30-90 of the video.

Track Selection

Select specific audio or video tracks:

/hls/video.mp4/tracks/v1-a2/master.m3u8

This selects video track 1 and audio track 2.

Time Shifting

Apply timestamp offsets:

/hls/video.mp4/shift/v100/master.m3u8

This shifts video timestamps by 100ms.

Performance Monitoring with Prometheus

Detailed performance metrics are available. Enable the status endpoint:

location /vod_status {
    vod_status;
    allow 10.0.0.0/8;
    deny all;
}

Access metrics in two formats:
– XML format: http://server/vod_status`
- Prometheus format:
http://server/vod_status?format=prom`

Key metrics to monitor:

  • vod_cache_fetch_hit / vod_cache_fetch_miss – Cache hit ratios
  • vod_perf_counter_sum{action="media_parse"} – MP4 parsing time
  • vod_perf_counter_sum{action="total"} – Total request processing time

Reset counters: `http://server/vod_status?reset=1`

SELinux Configuration on RHEL-Based Systems

When SELinux is enforcing, set the correct context for video files:

semanage fcontext -a -t httpd_sys_content_t '/var/www/videos(/.*)?'
restorecon -Rv /var/www/videos

Asynchronous I/O for High Performance

Enable asynchronous file operations for improved throughput:

http {
    # Enable AIO
    aio on;

    # Use thread pool for file opening (nginx 1.7.11+)
    thread_pool default threads=32 max_queue=65536;

    server {
        location /hls/ {
            alias /var/www/videos/;
            vod hls;
            vod_mode local;

            # Use thread pool for file opening
            vod_open_file_thread_pool default;

            # File handle caching
            open_file_cache max=1000 inactive=5m;
            open_file_cache_valid 2m;
            open_file_cache_min_uses 1;
            open_file_cache_errors on;
        }
    }
}

Monitor async operations via the status page. Look for async_open_file counters.

Remote Mode for Distributed Storage

Read MP4 files from HTTP backends like S3 or origin servers:

location /hls/ {
    vod hls;
    vod_mode remote;
    vod_upstream_location /storage;

    # Optimize remote reads
    vod_initial_read_size 32k;
    vod_max_metadata_size 256m;
}

location /storage {
    internal;
    proxy_pass http://s3.amazonaws.com/video-bucket;
    proxy_set_header Host s3.amazonaws.com;
}

Multi-Bitrate Adaptive Streaming

Serve multiple quality levels with a single URL structure. Use the multi-URL format:

/hls/videos/movie_,480p,720p,1080p,.mp4.urlset/master.m3u8

This generates a master playlist containing:
http://server/hls/videos/movie_480p.mp4/index.m3u8`
-
http://server/hls/videos/movie_720p.mp4/index.m3u8`
– `http://server/hls/videos/movie_1080p.mp4/index.m3u8`

Players automatically switch between quality levels based on bandwidth.

Available Variables

Several variables are exposed for use in configurations:

Variable Description
$vod_filepath Current file path
$vod_suburi Current sub-URI in multi-URL requests
$vod_set_id Media set identifier
$vod_sequence_id Current sequence identifier
$vod_segment_time Segment timestamp (milliseconds since epoch)
$vod_segment_duration Segment duration in milliseconds
$vod_status Internal error code for debugging

Use these for logging, access control, or DRM integrations.

Troubleshooting Common Issues

403 Forbidden Errors

Check file permissions and SELinux context:

ls -laZ /var/www/videos/
namei -l /var/www/videos/video.mp4

“ngx_file_reader” Errors

Ensure the file exists. Check the error log for the exact path.

Empty or Invalid Manifests

Verify the MP4 file has valid metadata:

ffprobe /var/www/videos/video.mp4

The moov atom must be at the file start. Use qt-faststart or ffmpeg -movflags +faststart.

Memory Issues

Increase cache sizes:

vod_metadata_cache metadata_cache 2g;
vod_max_metadata_size 256m;

Conclusion

The NGINX VOD module provides a robust foundation for video-on-demand delivery. It dynamically repackages content. This eliminates storage overhead from pre-transcoding. All major streaming protocols are supported. Deploy sophisticated video delivery infrastructure using the configurations in this guide.

For high-traffic deployments, combine with CDN caching. Edge locations serve manifests and segments. The origin handles on-the-fly packaging for cache misses.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.