+
netlify
+
groovy
+
cargo
arch
sinatra
+
rubymine
+
matplotlib
zorin
+
+
sinatra
+
+
+
+
+
babel
+
dynamo
+
supabase
axum
css
#
...
+
+
goland
+
+
+
+
npm
∞
+
mocha
phoenix
+
+
+
+
+
+
+
+
grafana
pascal
@
java
+
prettier
===
+
+
+
nvim
+
circle
erlang
+
swift
choo
+
+
cargo
+
macos
+
fortran
phpstorm
?
+
chef
+
+
protobuf
actix
+
yarn
+
+
+
+
+
+
Back to Blog
alpine-linux video-streaming nginx

Configuring Video Streaming on Alpine Linux 📹

Published Jun 13, 2025

Build a complete video streaming solution on Alpine Linux. Learn to set up streaming servers, configure live broadcasting, implement adaptive bitrate streaming, and optimize for performance.

5 min read
0 views
Table of Contents

Alpine Linux’s minimal footprint makes it an excellent choice for video streaming servers. This guide will help you build a professional video streaming infrastructure capable of handling live broadcasts, video-on-demand, and adaptive bitrate streaming.

Table of Contents

Prerequisites

Before setting up video streaming, ensure you have:

  • Alpine Linux with at least 4GB RAM (8GB+ recommended)
  • High-speed network connection (1Gbps+ for production)
  • Sufficient storage for video files
  • Basic understanding of video codecs and streaming protocols
  • Domain name for public streaming (optional)
  • SSL certificate for HTTPS streaming

Understanding Video Streaming

Streaming Protocols

# Check system resources
free -h
df -h
cat /proc/cpuinfo | grep "model name" | head -1

Key protocols:

  • RTMP: Real-Time Messaging Protocol (ingestion)
  • HLS: HTTP Live Streaming (delivery)
  • DASH: Dynamic Adaptive Streaming over HTTP
  • WebRTC: Real-time communication

Installing NGINX with RTMP

Step 1: Build NGINX with RTMP Module

# Install build dependencies
apk add build-base pcre-dev openssl-dev zlib-dev linux-headers

# Create build directory
mkdir -p /tmp/nginx-build
cd /tmp/nginx-build

# Download NGINX source
NGINX_VERSION="1.24.0"
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -xzf nginx-${NGINX_VERSION}.tar.gz

# Download RTMP module
git clone https://github.com/arut/nginx-rtmp-module.git

# Configure and build NGINX
cd nginx-${NGINX_VERSION}
./configure \
    --prefix=/etc/nginx \
    --sbin-path=/usr/sbin/nginx \
    --modules-path=/usr/lib/nginx/modules \
    --conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/var/run/nginx.pid \
    --lock-path=/var/run/nginx.lock \
    --http-client-body-temp-path=/var/cache/nginx/client_temp \
    --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
    --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
    --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
    --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
    --user=nginx \
    --group=nginx \
    --with-http_ssl_module \
    --with-http_realip_module \
    --with-http_addition_module \
    --with-http_sub_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_mp4_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_random_index_module \
    --with-http_secure_link_module \
    --with-http_stub_status_module \
    --with-http_auth_request_module \
    --with-http_xslt_module=dynamic \
    --with-http_image_filter_module=dynamic \
    --with-http_geoip_module=dynamic \
    --with-threads \
    --with-stream \
    --with-stream_ssl_module \
    --with-stream_ssl_preread_module \
    --with-stream_realip_module \
    --with-stream_geoip_module=dynamic \
    --with-http_slice_module \
    --with-http_v2_module \
    --add-module=../nginx-rtmp-module

# Compile and install
make -j$(nproc)
make install

Step 2: Create NGINX Service

# Create nginx user
adduser -D -s /sbin/nologin nginx

# Create directories
mkdir -p /var/cache/nginx/{client_temp,proxy_temp,fastcgi_temp,uwsgi_temp,scgi_temp}
mkdir -p /var/log/nginx
mkdir -p /etc/nginx/conf.d

# Set permissions
chown -R nginx:nginx /var/cache/nginx
chown -R nginx:nginx /var/log/nginx

# Create init script
cat > /etc/init.d/nginx << 'EOF'
#!/sbin/openrc-run

description="Nginx HTTP and reverse proxy server"
command="/usr/sbin/nginx"
command_args=""
pidfile="/var/run/nginx.pid"
extra_started_commands="reload"

depend() {
    need net
    use dns logger netmount
}

start_pre() {
    checkpath --directory --owner nginx:nginx --mode 0755 /var/log/nginx
    /usr/sbin/nginx -t -q
}

reload() {
    ebegin "Reloading nginx"
    /usr/sbin/nginx -s reload
    eend $?
}
EOF

chmod +x /etc/init.d/nginx

Configuring RTMP Streaming

Step 1: Basic RTMP Configuration

# Create NGINX configuration with RTMP
cat > /etc/nginx/nginx.conf << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
    use epoll;
}

# RTMP configuration
rtmp {
    server {
        listen 1935;
        chunk_size 4096;
        
        # Live streaming application
        application live {
            live on;
            
            # Record all streams
            record all;
            record_path /var/recordings;
            record_unique on;
            record_suffix .flv;
            
            # Allow publishing from localhost only
            allow publish 127.0.0.1;
            deny publish all;
            
            # Allow playback from anywhere
            allow play all;
            
            # Push to HLS
            exec_push /usr/bin/ffmpeg -i rtmp://localhost/live/$name
                -c:v libx264 -c:a aac -b:v 2500k -b:a 128k -f flv 
                rtmp://localhost/hls/$name 2>>/var/log/nginx/ffmpeg-$name.log;
        }
        
        # HLS application
        application hls {
            live on;
            hls on;
            hls_path /var/www/hls;
            hls_fragment 3s;
            hls_playlist_length 60s;
            
            # Disable consuming the stream from RTMP
            deny play all;
        }
    }
}

# HTTP configuration
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    
    access_log /var/log/nginx/access.log main;
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
    
    # Include additional configurations
    include /etc/nginx/conf.d/*.conf;
}
EOF

Step 2: Streaming Server Configuration

# Create streaming server configuration
cat > /etc/nginx/conf.d/streaming.conf << 'EOF'
server {
    listen 80;
    server_name stream.example.com;
    
    # Redirect to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name stream.example.com;
    
    # SSL configuration
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    
    # RTMP statistics
    location /stat {
        rtmp_stat all;
        rtmp_stat_stylesheet stat.xsl;
    }
    
    location /stat.xsl {
        root /etc/nginx/html;
    }
    
    # HLS streaming
    location /hls {
        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }
        
        root /var/www;
        
        # CORS headers
        add_header Access-Control-Allow-Origin *;
        add_header Cache-Control no-cache;
        
        # Disable cache
        expires -1;
    }
    
    # DASH streaming
    location /dash {
        root /var/www;
        
        types {
            application/dash+xml mpd;
            video/mp4 mp4;
        }
        
        add_header Access-Control-Allow-Origin *;
        add_header Cache-Control no-cache;
    }
    
    # Video player
    location / {
        root /var/www/html;
        index index.html;
    }
    
    # Control interface
    location /control {
        rtmp_control all;
    }
}
EOF

Setting Up HLS Streaming

Step 1: HLS Configuration

# Create HLS directories
mkdir -p /var/www/hls
chown -R nginx:nginx /var/www/hls

# Enhanced HLS configuration
cat > /etc/nginx/conf.d/hls-advanced.conf << 'EOF'
# Advanced HLS configuration
location /hls {
    types {
        application/vnd.apple.mpegurl m3u8;
        video/mp2t ts;
    }
    
    root /var/www;
    
    # CORS configuration
    if ($request_method = 'OPTIONS') {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, OPTIONS';
        add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header Access-Control-Max-Age 1728000;
        add_header Content-Type 'text/plain; charset=utf-8';
        add_header Content-Length 0;
        return 204;
    }
    
    add_header Access-Control-Allow-Origin * always;
    add_header Cache-Control no-cache;
    
    # Client caching
    location ~ \.ts$ {
        add_header Cache-Control "public, max-age=3600";
    }
    
    location ~ \.m3u8$ {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma no-cache;
        add_header Expires 0;
    }
}
EOF

Step 2: HLS Player Setup

# Create web player
mkdir -p /var/www/html
cat > /var/www/html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Live Stream Player</title>
    <link href="https://vjs.zencdn.net/7.20.3/video-js.css" rel="stylesheet">
    <style>
        body {
            margin: 0;
            padding: 20px;
            font-family: Arial, sans-serif;
            background: #1a1a1a;
            color: #fff;
        }
        .video-container {
            max-width: 1280px;
            margin: 0 auto;
        }
        .video-js {
            width: 100%;
            height: auto;
            aspect-ratio: 16/9;
        }
        .stream-info {
            margin-top: 20px;
            padding: 15px;
            background: #2a2a2a;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div class="video-container">
        <video id="player" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto">
            <source src="/hls/stream.m3u8" type="application/x-mpegURL">
        </video>
        
        <div class="stream-info">
            <h3>Stream Information</h3>
            <div id="stats"></div>
        </div>
    </div>
    
    <script src="https://vjs.zencdn.net/7.20.3/video.min.js"></script>
    <script>
        var player = videojs('player', {
            autoplay: true,
            controls: true,
            fluid: true,
            liveui: true
        });
        
        // Update statistics
        function updateStats() {
            fetch('/stat')
                .then(response => response.text())
                .then(data => {
                    // Parse and display statistics
                    document.getElementById('stats').innerHTML = 'Connected';
                });
        }
        
        setInterval(updateStats, 5000);
    </script>
</body>
</html>
EOF

Implementing DASH Streaming

Step 1: DASH Configuration

# Create DASH directory
mkdir -p /var/www/dash
chown -R nginx:nginx /var/www/dash

# Update RTMP configuration for DASH
cat >> /etc/nginx/nginx.conf << 'EOF'

        # DASH application
        application dash {
            live on;
            dash on;
            dash_path /var/www/dash;
            dash_fragment 3s;
            dash_playlist_length 60s;
            
            # Disable consuming the stream from RTMP
            deny play all;
        }
EOF

Step 2: DASH Transcoding

# Create DASH transcoding script
cat > /usr/local/bin/transcode-dash.sh << 'EOF'
#!/bin/sh
# Transcode to DASH with multiple bitrates

INPUT="$1"
OUTPUT_DIR="/var/www/dash"
STREAM_NAME=$(basename "$INPUT" .flv)

# Create output directory
mkdir -p "$OUTPUT_DIR/$STREAM_NAME"

# Transcode to multiple bitrates
ffmpeg -re -i "$INPUT" \
    -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 \
    -c:v libx264 -crf 22 -c:a aac -ar 48000 \
    -filter:v:0 scale=w=480:h=270 -maxrate:v:0 600k -b:a:0 64k \
    -filter:v:1 scale=w=640:h=360 -maxrate:v:1 900k -b:a:1 128k \
    -filter:v:2 scale=w=1280:h=720 -maxrate:v:2 2500k -b:a:2 192k \
    -var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
    -seg_duration 3 -use_template 1 -use_timeline 1 \
    -adaptation_sets "id=0,streams=v id=1,streams=a" \
    -f dash "$OUTPUT_DIR/$STREAM_NAME/manifest.mpd"
EOF

chmod +x /usr/local/bin/transcode-dash.sh

Video Transcoding Setup

Step 1: Install FFmpeg

# Install FFmpeg with full codec support
apk add ffmpeg ffmpeg-libs ffmpeg-dev

# Install additional codecs
apk add x264-libs x265 libvpx libvorbis opus-dev

Step 2: Transcoding Profiles

# Create transcoding profiles script
cat > /usr/local/bin/transcode-profiles.sh << 'EOF'
#!/bin/sh
# Video transcoding profiles

INPUT="$1"
OUTPUT_BASE="/var/www/vod"
STREAM_KEY=$(basename "$INPUT" | cut -d. -f1)

# Create output directory
mkdir -p "$OUTPUT_BASE/$STREAM_KEY"

# Source video information
eval $(ffprobe -v error -select_streams v:0 \
    -show_entries stream=width,height,r_frame_rate \
    -of default=noprint_wrappers=1 "$INPUT")

# Calculate frame rate
FPS=$(echo $r_frame_rate | bc -l | cut -d. -f1)

# Transcoding function
transcode_variant() {
    local width=$1
    local height=$2
    local bitrate=$3
    local audio_bitrate=$4
    local profile=$5
    
    echo "Transcoding ${width}x${height} @ ${bitrate}k..."
    
    ffmpeg -i "$INPUT" \
        -c:v libx264 -profile:v $profile \
        -preset medium -crf 23 \
        -maxrate ${bitrate}k -bufsize $((bitrate*2))k \
        -vf "scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2" \
        -c:a aac -b:a ${audio_bitrate}k -ar 44100 \
        -movflags +faststart \
        -y "$OUTPUT_BASE/$STREAM_KEY/${width}x${height}.mp4"
}

# Generate variants based on source resolution
if [ $width -ge 1920 ]; then
    transcode_variant 1920 1080 5000 192 high
    transcode_variant 1280 720 2500 128 main
    transcode_variant 854 480 1200 96 main
    transcode_variant 640 360 800 96 baseline
elif [ $width -ge 1280 ]; then
    transcode_variant 1280 720 2500 128 main
    transcode_variant 854 480 1200 96 main
    transcode_variant 640 360 800 96 baseline
else
    transcode_variant $width $height 1200 128 main
fi

# Generate HLS playlist
echo "Generating HLS playlist..."
ffmpeg -i "$INPUT" \
    -c:v copy -c:a copy \
    -f hls -hls_time 6 -hls_list_size 0 \
    -hls_segment_filename "$OUTPUT_BASE/$STREAM_KEY/segment_%03d.ts" \
    "$OUTPUT_BASE/$STREAM_KEY/playlist.m3u8"

echo "Transcoding complete for $STREAM_KEY"
EOF

chmod +x /usr/local/bin/transcode-profiles.sh

Live Streaming Configuration

Step 1: Stream Ingestion Setup

# Create stream authentication script
cat > /usr/local/bin/stream-auth.sh << 'EOF'
#!/bin/sh
# Stream authentication script

# Get stream key from URL
STREAM_KEY="$1"

# Validate stream key (implement your logic)
VALID_KEYS="/etc/nginx/stream_keys.txt"

if grep -q "^${STREAM_KEY}$" "$VALID_KEYS"; then
    exit 0  # Allow
else
    exit 1  # Deny
fi
EOF

chmod +x /usr/local/bin/stream-auth.sh

# Create stream keys file
touch /etc/nginx/stream_keys.txt
chmod 600 /etc/nginx/stream_keys.txt

Step 2: Advanced RTMP Configuration

# Update RTMP configuration with authentication
cat > /etc/nginx/rtmp-advanced.conf << 'EOF'
rtmp {
    server {
        listen 1935;
        ping 30s;
        notify_method get;
        
        application live {
            live on;
            
            # Stream authentication
            on_publish http://localhost/auth/publish;
            on_publish_done http://localhost/auth/publish_done;
            
            # Allow only authenticated publishers
            allow publish all;
            allow play all;
            
            # Record streams
            record all;
            record_path /var/recordings;
            record_unique on;
            record_suffix .flv;
            
            # Notify on events
            on_play http://localhost/events/play;
            on_play_done http://localhost/events/play_done;
            
            # Multi-bitrate transcoding
            exec_push /usr/local/bin/transcode-live.sh $name;
            
            # Push to multiple outputs
            # push rtmp://youtube.com/live/STREAM_KEY;
            # push rtmp://twitch.tv/live/STREAM_KEY;
        }
        
        # Transcoded streams
        application show {
            live on;
            
            # Different quality streams
            # Original
            on_publish http://localhost/auth/transcode;
            
            # HLS output
            hls on;
            hls_path /var/www/hls;
            hls_fragment 3s;
            hls_playlist_length 60s;
            
            # Variants
            hls_variant _low BANDWIDTH=800000;
            hls_variant _mid BANDWIDTH=1200000;
            hls_variant _high BANDWIDTH=2500000;
        }
    }
}
EOF

Step 3: Live Transcoding Script

# Create live transcoding script
cat > /usr/local/bin/transcode-live.sh << 'EOF'
#!/bin/sh
# Live stream transcoding

STREAM_KEY="$1"
RTMP_URL="rtmp://localhost/live/$STREAM_KEY"

# Low quality
ffmpeg -i "$RTMP_URL" \
    -c:v libx264 -preset veryfast -tune zerolatency \
    -vf scale=640:360 -b:v 800k -maxrate 800k -bufsize 800k \
    -c:a aac -b:a 96k -ar 44100 \
    -f flv "rtmp://localhost/show/${STREAM_KEY}_low" \
    2>/var/log/nginx/transcode-${STREAM_KEY}-low.log &

# Medium quality
ffmpeg -i "$RTMP_URL" \
    -c:v libx264 -preset veryfast -tune zerolatency \
    -vf scale=854:480 -b:v 1200k -maxrate 1200k -bufsize 1200k \
    -c:a aac -b:a 128k -ar 44100 \
    -f flv "rtmp://localhost/show/${STREAM_KEY}_mid" \
    2>/var/log/nginx/transcode-${STREAM_KEY}-mid.log &

# High quality
ffmpeg -i "$RTMP_URL" \
    -c:v copy \
    -c:a copy \
    -f flv "rtmp://localhost/show/${STREAM_KEY}_high" \
    2>/var/log/nginx/transcode-${STREAM_KEY}-high.log &

# Save PIDs for cleanup
echo $! > /var/run/transcode-${STREAM_KEY}.pid
EOF

chmod +x /usr/local/bin/transcode-live.sh

Video on Demand (VOD)

Step 1: VOD Configuration

# Create VOD directory structure
mkdir -p /var/www/vod/{videos,thumbnails,metadata}
chown -R nginx:nginx /var/www/vod

# VOD server configuration
cat > /etc/nginx/conf.d/vod.conf << 'EOF'
server {
    listen 8080;
    server_name vod.example.com;
    
    root /var/www/vod;
    
    # MP4 streaming
    location ~ \.mp4$ {
        mp4;
        mp4_buffer_size 1m;
        mp4_max_buffer_size 5m;
        
        # Enable seeking
        add_header Accept-Ranges bytes;
        
        # CORS
        add_header Access-Control-Allow-Origin *;
        
        # Cache control
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
    
    # Thumbnail serving
    location /thumbnails {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    
    # Video metadata API
    location /api/videos {
        default_type application/json;
        content_by_lua_block {
            -- Implement video listing logic
        }
    }
    
    # Pseudo-streaming for FLV
    location ~ \.flv$ {
        flv;
    }
}
EOF

Step 2: VOD Processing Pipeline

# Create VOD processing script
cat > /usr/local/bin/process-vod.sh << 'EOF'
#!/bin/sh
# VOD processing pipeline

INPUT_FILE="$1"
VIDEO_ID=$(uuidgen)
VOD_DIR="/var/www/vod"

# Directories
VIDEO_DIR="$VOD_DIR/videos/$VIDEO_ID"
THUMB_DIR="$VOD_DIR/thumbnails/$VIDEO_ID"
META_FILE="$VOD_DIR/metadata/$VIDEO_ID.json"

mkdir -p "$VIDEO_DIR" "$THUMB_DIR"

# Get video information
DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")
WIDTH=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")
HEIGHT=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")

# Generate thumbnails
for i in 1 2 3 4 5; do
    TIME=$(echo "$DURATION * $i / 6" | bc)
    ffmpeg -ss "$TIME" -i "$INPUT_FILE" -vframes 1 -vf scale=320:180 "$THUMB_DIR/thumb_$i.jpg" -y
done

# Create preview gif
ffmpeg -i "$INPUT_FILE" -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -t 5 "$THUMB_DIR/preview.gif"

# Transcode video
/usr/local/bin/transcode-profiles.sh "$INPUT_FILE"

# Generate metadata
cat > "$META_FILE" << EOJ
{
    "id": "$VIDEO_ID",
    "filename": "$(basename "$INPUT_FILE")",
    "duration": $DURATION,
    "width": $WIDTH,
    "height": $HEIGHT,
    "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "variants": [
        {"quality": "1080p", "url": "/videos/$VIDEO_ID/1920x1080.mp4"},
        {"quality": "720p", "url": "/videos/$VIDEO_ID/1280x720.mp4"},
        {"quality": "480p", "url": "/videos/$VIDEO_ID/854x480.mp4"},
        {"quality": "360p", "url": "/videos/$VIDEO_ID/640x360.mp4"}
    ],
    "thumbnails": [
        "/thumbnails/$VIDEO_ID/thumb_1.jpg",
        "/thumbnails/$VIDEO_ID/thumb_2.jpg",
        "/thumbnails/$VIDEO_ID/thumb_3.jpg",
        "/thumbnails/$VIDEO_ID/thumb_4.jpg",
        "/thumbnails/$VIDEO_ID/thumb_5.jpg"
    ],
    "preview": "/thumbnails/$VIDEO_ID/preview.gif"
}
EOJ

echo "VOD processing complete: $VIDEO_ID"
EOF

chmod +x /usr/local/bin/process-vod.sh

Adaptive Bitrate Streaming

Step 1: ABR Implementation

# Create ABR manifest generator
cat > /usr/local/bin/generate-abr-manifest.sh << 'EOF'
#!/bin/sh
# Generate adaptive bitrate manifest

VIDEO_ID="$1"
BASE_URL="https://stream.example.com"
VOD_DIR="/var/www/vod/videos/$VIDEO_ID"

# Create master playlist
cat > "$VOD_DIR/master.m3u8" << EOM
#EXTM3U
#EXT-X-VERSION:3

# 1080p
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2"
${BASE_URL}/vod/videos/${VIDEO_ID}/1080p/playlist.m3u8

# 720p
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2"
${BASE_URL}/vod/videos/${VIDEO_ID}/720p/playlist.m3u8

# 480p
#EXT-X-STREAM-INF:BANDWIDTH=1200000,RESOLUTION=854x480,CODECS="avc1.64001e,mp4a.40.2"
${BASE_URL}/vod/videos/${VIDEO_ID}/480p/playlist.m3u8

# 360p
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360,CODECS="avc1.64001e,mp4a.40.2"
${BASE_URL}/vod/videos/${VIDEO_ID}/360p/playlist.m3u8
EOM

# Generate HLS segments for each quality
for quality in 1080p 720p 480p 360p; do
    mkdir -p "$VOD_DIR/$quality"
    
    case $quality in
        1080p) res="1920x1080" ;;
        720p) res="1280x720" ;;
        480p) res="854x480" ;;
        360p) res="640x360" ;;
    esac
    
    if [ -f "$VOD_DIR/${res}.mp4" ]; then
        ffmpeg -i "$VOD_DIR/${res}.mp4" \
            -c copy -f hls \
            -hls_time 6 \
            -hls_list_size 0 \
            -hls_segment_filename "$VOD_DIR/$quality/segment_%03d.ts" \
            "$VOD_DIR/$quality/playlist.m3u8"
    fi
done

echo "ABR manifest generated for $VIDEO_ID"
EOF

chmod +x /usr/local/bin/generate-abr-manifest.sh

Step 2: Bandwidth Detection

# Create bandwidth detection endpoint
cat > /var/www/html/bandwidth-test.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Bandwidth Test</title>
</head>
<body>
    <script>
    function measureBandwidth() {
        const testSize = 1048576; // 1MB
        const testUrl = '/test-file.bin';
        const startTime = Date.now();
        
        fetch(testUrl)
            .then(response => response.blob())
            .then(blob => {
                const endTime = Date.now();
                const duration = (endTime - startTime) / 1000; // seconds
                const bitsLoaded = blob.size * 8;
                const bandwidth = bitsLoaded / duration;
                
                console.log(`Bandwidth: ${(bandwidth / 1000000).toFixed(2)} Mbps`);
                
                // Store bandwidth for player
                localStorage.setItem('estimatedBandwidth', bandwidth);
            });
    }
    
    // Test on load
    measureBandwidth();
    
    // Periodic testing
    setInterval(measureBandwidth, 30000);
    </script>
</body>
</html>
EOF

# Generate test file
dd if=/dev/urandom of=/var/www/html/test-file.bin bs=1M count=1

Security and Authentication

Step 1: Stream Key Management

# Create stream key management script
cat > /usr/local/bin/manage-stream-keys.sh << 'EOF'
#!/bin/sh
# Stream key management

KEYS_FILE="/etc/nginx/stream_keys.txt"
KEYS_DB="/var/lib/streaming/keys.db"

case "$1" in
    add)
        KEY=$(openssl rand -hex 16)
        USER="$2"
        echo "$KEY # $USER - Added $(date)" >> "$KEYS_FILE"
        echo "Stream key for $USER: $KEY"
        ;;
    remove)
        KEY="$2"
        sed -i "/^$KEY/d" "$KEYS_FILE"
        echo "Removed key: $KEY"
        ;;
    list)
        cat "$KEYS_FILE"
        ;;
    *)
        echo "Usage: $0 {add|remove|list} [user|key]"
        exit 1
        ;;
esac

# Reload NGINX
nginx -s reload
EOF

chmod +x /usr/local/bin/manage-stream-keys.sh

Step 2: Secure Token Authentication

# Create secure token module configuration
cat > /etc/nginx/conf.d/secure-token.conf << 'EOF'
# Secure token for VOD
location /secure/ {
    secure_link $arg_md5,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri SECRET_KEY";
    
    if ($secure_link = "") {
        return 403;
    }
    
    if ($secure_link = "0") {
        return 410;
    }
    
    # Serve video
    rewrite ^/secure/(.*)$ /vod/$1 last;
}

# Token generation endpoint
location /api/generate-token {
    content_by_lua_block {
        local expires = ngx.time() + 3600 -- 1 hour
        local uri = ngx.var.arg_uri
        local secret = "SECRET_KEY"
        
        local string_to_hash = expires .. uri .. secret
        local md5 = ngx.md5(string_to_hash)
        
        local token_url = "/secure" .. uri .. "?md5=" .. md5 .. "&expires=" .. expires
        
        ngx.header.content_type = "application/json"
        ngx.say('{"url":"' .. token_url .. '","expires":' .. expires .. '}')
    }
}
EOF

Performance Optimization

Step 1: NGINX Optimization

# Update NGINX configuration for performance
cat > /etc/nginx/nginx-optimized.conf << 'EOF'
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

http {
    # Basic settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    
    # Buffer sizes
    client_body_buffer_size 128k;
    client_max_body_size 0;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 4k;
    output_buffers 32 32k;
    postpone_output 1460;
    
    # Timeouts
    client_header_timeout 10s;
    client_body_timeout 10s;
    send_timeout 10s;
    keepalive_timeout 65s;
    keepalive_requests 100;
    
    # File cache
    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
    
    # Gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
    
    # Rate limiting
    limit_req_zone $binary_remote_addr zone=streaming:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;
}
EOF

Step 2: System Tuning

# Create system tuning script
cat > /usr/local/bin/tune-streaming-server.sh << 'EOF'
#!/bin/sh
# System tuning for streaming

# Network tuning
cat >> /etc/sysctl.conf << EOC
# Network performance tuning
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_slow_start_after_idle = 0

# Connection handling
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
EOC

sysctl -p

# File system tuning
echo "fs.file-max = 1000000" >> /etc/sysctl.conf

# Set ulimits
cat >> /etc/security/limits.conf << EOL
nginx soft nofile 65535
nginx hard nofile 65535
nginx soft nproc 65535
nginx hard nproc 65535
EOL

echo "System tuning applied"
EOF

chmod +x /usr/local/bin/tune-streaming-server.sh

Monitoring and Analytics

Step 1: Streaming Analytics

# Create analytics collection script
cat > /usr/local/bin/collect-streaming-stats.sh << 'EOF'
#!/bin/sh
# Collect streaming statistics

STATS_DIR="/var/log/streaming/stats"
DATE=$(date +%Y%m%d_%H%M%S)
STATS_FILE="$STATS_DIR/stats_$DATE.json"

mkdir -p "$STATS_DIR"

# Get RTMP statistics
curl -s http://localhost/stat | \
    xmlstarlet sel -t -m "//application/live/stream" \
    -o '{"name":"' -v "name" -o '",' \
    -o '"time":"' -v "time" -o '",' \
    -o '"bw_in":"' -v "bw_in" -o '",' \
    -o '"bytes_in":"' -v "bytes_in" -o '",' \
    -o '"bw_out":"' -v "bw_out" -o '",' \
    -o '"bytes_out":"' -v "bytes_out" -o '",' \
    -o '"clients":"' -v "nclients" -o '"}' -n \
    > "$STATS_FILE"

# Parse NGINX access logs
awk '$9 ~ /^2/ {print $1}' /var/log/nginx/access.log | \
    sort | uniq -c | sort -rn | head -20 > "$STATS_DIR/top_ips_$DATE.txt"

# Bandwidth usage
vnstat -i eth0 --json > "$STATS_DIR/bandwidth_$DATE.json"

# Clean old stats
find "$STATS_DIR" -name "*.json" -mtime +7 -delete
find "$STATS_DIR" -name "*.txt" -mtime +7 -delete
EOF

chmod +x /usr/local/bin/collect-streaming-stats.sh

# Add to cron
echo "*/5 * * * * /usr/local/bin/collect-streaming-stats.sh" >> /etc/crontabs/root

Step 2: Monitoring Dashboard

# Create monitoring dashboard
cat > /var/www/html/dashboard.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Streaming Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background: #f5f5f5;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }
        .stat-card {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .stat-value {
            font-size: 2em;
            font-weight: bold;
            color: #333;
        }
        .stat-label {
            color: #666;
            margin-top: 5px;
        }
        .chart-container {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Streaming Server Dashboard</h1>
        
        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-value" id="active-streams">0</div>
                <div class="stat-label">Active Streams</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="total-viewers">0</div>
                <div class="stat-label">Total Viewers</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="bandwidth-usage">0 Mbps</div>
                <div class="stat-label">Bandwidth Usage</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="server-uptime">0h</div>
                <div class="stat-label">Server Uptime</div>
            </div>
        </div>
        
        <div class="chart-container">
            <canvas id="viewersChart"></canvas>
        </div>
        
        <div class="chart-container">
            <canvas id="bandwidthChart"></canvas>
        </div>
    </div>
    
    <script>
        // Initialize charts
        const viewersCtx = document.getElementById('viewersChart').getContext('2d');
        const viewersChart = new Chart(viewersCtx, {
            type: 'line',
            data: {
                labels: [],
                datasets: [{
                    label: 'Concurrent Viewers',
                    data: [],
                    borderColor: 'rgb(75, 192, 192)',
                    tension: 0.1
                }]
            },
            options: {
                responsive: true,
                plugins: {
                    title: {
                        display: true,
                        text: 'Viewers Over Time'
                    }
                }
            }
        });
        
        // Update function
        function updateStats() {
            fetch('/api/stats')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('active-streams').textContent = data.streams;
                    document.getElementById('total-viewers').textContent = data.viewers;
                    document.getElementById('bandwidth-usage').textContent = data.bandwidth + ' Mbps';
                    document.getElementById('server-uptime').textContent = data.uptime;
                    
                    // Update charts
                    const now = new Date().toLocaleTimeString();
                    viewersChart.data.labels.push(now);
                    viewersChart.data.datasets[0].data.push(data.viewers);
                    
                    // Keep last 20 data points
                    if (viewersChart.data.labels.length > 20) {
                        viewersChart.data.labels.shift();
                        viewersChart.data.datasets[0].data.shift();
                    }
                    
                    viewersChart.update();
                });
        }
        
        // Update every 5 seconds
        setInterval(updateStats, 5000);
        updateStats();
    </script>
</body>
</html>
EOF

CDN Integration

Step 1: CDN Push Configuration

# Create CDN push script
cat > /usr/local/bin/push-to-cdn.sh << 'EOF'
#!/bin/sh
# Push streams to CDN

STREAM_KEY="$1"
CDN_ENDPOINTS="/etc/nginx/cdn_endpoints.conf"

# Read CDN endpoints
while IFS='=' read -r name url; do
    if [ -n "$name" ] && [ -n "$url" ]; then
        echo "Pushing to $name"
        ffmpeg -re -i "rtmp://localhost/live/$STREAM_KEY" \
            -c copy -f flv "$url/$STREAM_KEY" \
            2>/var/log/nginx/cdn-push-${name}-${STREAM_KEY}.log &
        
        # Save PID for cleanup
        echo $! > "/var/run/cdn-push-${name}-${STREAM_KEY}.pid"
    fi
done < "$CDN_ENDPOINTS"
EOF

chmod +x /usr/local/bin/push-to-cdn.sh

# Create CDN endpoints configuration
cat > /etc/nginx/cdn_endpoints.conf << 'EOF'
# CDN Endpoints
primary=rtmp://cdn1.example.com/live
backup=rtmp://cdn2.example.com/live
# youtube=rtmp://a.rtmp.youtube.com/live2
# twitch=rtmp://live.twitch.tv/app
EOF

Step 2: CDN Origin Configuration

# Configure as CDN origin
cat > /etc/nginx/conf.d/cdn-origin.conf << 'EOF'
# CDN Origin Configuration
server {
    listen 80;
    server_name origin.example.com;
    
    # HLS origin
    location /hls {
        root /var/www;
        
        # Allow CDN servers only
        allow 10.0.0.0/8;
        allow 172.16.0.0/12;
        deny all;
        
        # Cache headers for CDN
        add_header Cache-Control "public, max-age=3600";
        add_header X-Content-Type-Options nosniff;
        
        # CORS for CDN
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "GET, OPTIONS";
    }
    
    # Purge cache endpoint
    location /purge {
        allow 127.0.0.1;
        deny all;
        
        # Implement cache purge logic
    }
}
EOF

Troubleshooting

Common Issues

  1. Stream buffering issues:
# Check NGINX error logs
tail -f /var/log/nginx/error.log

# Monitor RTMP connections
netstat -an | grep 1935

# Check FFmpeg logs
tail -f /var/log/nginx/ffmpeg-*.log
  1. High CPU usage:
# Monitor FFmpeg processes
htop -p $(pgrep ffmpeg | tr '\n' ',')

# Optimize encoding settings
# Use hardware acceleration if available
ffmpeg -hwaccels
  1. Stream authentication fails:
# Check auth script
sh -x /usr/local/bin/stream-auth.sh test-key

# Verify stream keys file
cat /etc/nginx/stream_keys.txt

# Test RTMP publish
ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost/live/test-key

Debug Configuration

# Enable debug logging
cat >> /etc/nginx/nginx.conf << 'EOF'
error_log /var/log/nginx/debug.log debug;

rtmp {
    access_log /var/log/nginx/rtmp_access.log;
}
EOF

# Monitor RTMP statistics
watch -n 1 'curl -s http://localhost/stat | grep -E "(nclients|time|bytes)"'

Best Practices

Production Checklist

# Create production setup script
cat > /usr/local/bin/production-setup.sh << 'EOF'
#!/bin/sh
# Production streaming server setup

echo "=== Production Setup Checklist ==="

# 1. Security
echo "[1] Configuring firewall..."
iptables -A INPUT -p tcp --dport 1935 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 1935 -j DROP

# 2. SSL certificates
echo "[2] Checking SSL certificates..."
certbot certificates

# 3. Monitoring
echo "[3] Setting up monitoring..."
apk add monit
cat > /etc/monit/conf.d/streaming << EOM
check process nginx with pidfile /var/run/nginx.pid
    start program = "/etc/init.d/nginx start"
    stop program = "/etc/init.d/nginx stop"
    if failed host localhost port 80 then restart
    if cpu > 80% for 5 cycles then alert
    if memory > 80% then alert
EOM

# 4. Backup configuration
echo "[4] Backing up configuration..."
tar -czf /backup/streaming-config-$(date +%Y%m%d).tar.gz \
    /etc/nginx \
    /usr/local/bin \
    /var/www/html

# 5. Performance testing
echo "[5] Running performance test..."
ab -n 1000 -c 100 http://localhost/hls/test.m3u8

echo "=== Setup Complete ==="
EOF

chmod +x /usr/local/bin/production-setup.sh

Maintenance Tasks

# Create maintenance script
cat > /etc/periodic/daily/streaming-maintenance << 'EOF'
#!/bin/sh
# Daily streaming server maintenance

# Clean old recordings
find /var/recordings -name "*.flv" -mtime +7 -delete

# Clean old logs
find /var/log/nginx -name "*.log" -mtime +30 -delete

# Rotate logs
/usr/sbin/logrotate /etc/logrotate.d/nginx

# Clean HLS segments
find /var/www/hls -name "*.ts" -mmin +60 -delete

# Update stream statistics
/usr/local/bin/collect-streaming-stats.sh

# Check disk space
df -h /var/www | mail -s "Streaming Server Disk Usage" [email protected]
EOF

chmod +x /etc/periodic/daily/streaming-maintenance

Conclusion

You’ve successfully configured a comprehensive video streaming solution on Alpine Linux. This setup supports multiple streaming protocols, adaptive bitrate streaming, live broadcasting, and video-on-demand services. The lightweight nature of Alpine Linux combined with NGINX’s efficiency provides a robust platform for streaming media.

Remember to regularly monitor your streams, optimize encoding settings based on your audience, and keep your security configurations updated. With proper maintenance and monitoring, this streaming server can handle professional broadcasting requirements while maintaining excellent performance.