Friday, August 18, 2017

Implement Nginx Reverse Proxy with SSL for Live Streaming

After struggling implement NGINX reverse proxy setup, I have decided to share my running config currently and hope this could be of any help to someone.

Here is the scenario of the implementation


First, we need to configure NGINX to enable http_v2_module
sudo ./configure  --with-http_ssl_module --with-http_v2_module  --add-module=../nginx-rtmp-module
make
sudo make install

After configure and compile NGINX, then in server 10.10.16.32 as reverse proxy, the configuration as following as below and don't forget to copy your SSL key and crt to your correct folder, in my case is in /home/livetv/live.

user livetv;
worker_processes  8;

error_log    /var/log/nginx/error.log debug;
worker_rlimit_nofile 65536;  #worker_rlimit_nofile = worker_connections * worker_processes

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

rtmp {
    server {
        listen 1935;
        chunk_size 8192;
        ping 30s;
        notify_method get;
        allow play all;

        application live {
            live on;

            exec_pull ffmpeg -re -i http://10.10.17.50/$app/$name
                 -vcodec copy -f flv -ar 44100 -ab 64 -ac 1 -acodec mp3 rtmp://localhost:1935/show/${name}
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_480
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 776k -b:a 96k -vf "scale=640:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_360
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 128k -b:a 96k -vf "scale=256:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_144;
        }

        application show {
            live on;
            hls on;
            hls_path /home/livetv/live/hls/;
            hls_nested on;
            record off;

            ### Instruct clients to adjust resolution according to bandwidth
            hls_variant _720 BANDWIDTH=2048000 RESOLUTION=1280x720; # High bitrate, HD 720p resolution
            hls_variant _480 BANDWIDTH=1024000 RESOLUTION=852x480;     # High bitrate, higher-than-SD resolution
            hls_variant _360 BANDWIDTH=512000 RESOLUTION=640x360;     # Medium bitrate, SD resolution
            hls_variant _240 BANDWIDTH=307200 RESOLUTION=426x240;     # Low bitrate, sub-SD resolution
            hls_variant _144 BANDWIDTH=131000 RESOLUTION=256x144;     # Low bitrate, 140p resolution
        }
       
        exec_pull /home/livetv/live/chmodTV.sh;
    }
}

http {
    include /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile on;
    keepalive_timeout   65;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    server {
        listen      8080;

        location /hls {
            # Disable cache
            add_header 'Cache-Control' 'no-cache';

            # CORS setup
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            add_header 'Access-Control-Allow-Headers' 'Range';

            # allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Allow-Headers' 'Range';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
            }

            #serve HLS fragments
            types {
                    application/dash+xml mpd;
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
            }

            root /home/livetv/live/;
            add_header Cache-Control no-cache;
        }

        #include /usr/local/nginx/conf/sites-enabled/*.conf;
    }

    server {
        listen 443 ssl http2;
        server_name cdn-livetv.metube.id;
        root /home/livetv/live/;

        ssl on;
        ssl_certificate /home/livetv/live/ssl/STAR_metube_id.crt;
        ssl_certificate_key /home/livetv/live/ssl/metube.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_buffer_size 16k;

        location / {
            index index.html;
        }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|txt|xml|js)$ {
            expires 21d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
            access_log off;
            log_not_found off;
            fastcgi_hide_header Set-Cookie;
            tcp_nodelay off;
            sendfile off;
            break;
        }

        location /hls {
            proxy_set_header x-real-IP $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
            proxy_set_header x-forwarded-proto https;
            proxy_set_header host $host;
            proxy_pass http://172.31.16.26;
           
            #this is will handle problem in mobile when rise protocol exception
            proxy_buffering on;
            proxy_buffer_size 8k;
            proxy_buffers 2048 8k;
        }
    }
}




In server 172.31.16.26 as backend, the configuration as following as below and don't forget to copy your SSL key and crt to your correct folder, in my case is in /home/livetv/live.


user livetv livetv;
worker_processes  20;

error_log  logs/error.log debug;
worker_rlimit_nofile 409600; #worker_rlimit_nofile = worker_connections * worker_processes

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

rtmp {
    server {
        listen 1935;
        chunk_size 8192;
        ping 30s;
        notify_method get;
        allow play all;

        application live {
            live on;

            exec_pull ffmpeg -re -i http://172.31.16.27/$app/$name
                 -vcodec copy -f flv -ar 44100 -ab 64 -ac 1 -acodec mp3 rtmp://localhost:1935/show/${name}
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 1024k -b:a 128k -vf "scale=854:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_480
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 776k -b:a 96k -vf "scale=640:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_360
                 -vcodec libx264 -threads 0 -vprofile baseline -acodec aac -strict -2 -b:v 128k -b:a 96k -vf "scale=256:trunc(ow/a/2)*2" -tune zerolatency -preset veryfast -crf 23 -f flv rtmp://localhost:1935/show/${name}_144;
        }

        application show {
            live on;
            hls on;
            hls_path /home/livetv/live/hls/;
            hls_nested on;
            record off;

            ### Instruct clients to adjust resolution according to bandwidth
            hls_variant _720 BANDWIDTH=2048000 RESOLUTION=1280x720; # High bitrate, HD 720p resolution
            hls_variant _480 BANDWIDTH=1024000 RESOLUTION=852x480;     # High bitrate, higher-than-SD resolution
            hls_variant _360 BANDWIDTH=512000 RESOLUTION=640x360;     # Medium bitrate, SD resolution
            hls_variant _240 BANDWIDTH=307200 RESOLUTION=426x240;     # Low bitrate, sub-SD resolution
            hls_variant _144 BANDWIDTH=131000 RESOLUTION=256x144;     # Low bitrate, 140p resolution

        }
    }
}


http {

    include mime.types;
    default_type  application/octet-stream;
    sendfile on;
    keepalive_timeout   65;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    server {
        listen      80;

        location /hls {
            # Disable cache
            add_header 'Cache-Control' 'no-cache';

            # CORS setup
            add_header 'Access-Control-Allow-Origin' '*' always;
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
            add_header 'Access-Control-Allow-Headers' 'Range';

            # allow CORS preflight requests
            if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Allow-Origin' '*';
                    add_header 'Access-Control-Allow-Headers' 'Range';
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain charset=UTF-8';
                    add_header 'Content-Length' 0;
                    return 204;
            }

            #serve HLS fragments
            types {
                    application/dash+xml mpd;
                    application/vnd.apple.mpegurl m3u8;
                    video/mp2t ts;
            }

            root /home/livetv/live/;
            add_header Cache-Control no-cache;
        }

        include /usr/local/nginx/conf/sites-enabled/*.conf;

    }

    server {
        listen 443 ssl http2;
        server_name cdn-livetv.metube.id;
        #rewrite ^(.*)  cdn-livetv.metube.id$1 permanent;
        root /home/livetv/live/;

        ssl on;
        ssl_certificate /home/livetv/live/ssl/STAR_metube_id.crt;
        ssl_certificate_key /home/livetv/live/ssl/metube.key;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;

        ssl_buffer_size 16k;
        location / {
            index index.html;
        }

        location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|pdf|txt|xml|js)$ {
            expires 21d;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
            access_log off;
            log_not_found off;
            fastcgi_hide_header Set-Cookie;
            tcp_nodelay off;
            sendfile off;
            break;
        }

        location /hls {
            proxy_set_header x-real-IP $remote_addr;
            proxy_set_header x-forwarded-for $proxy_add_x_forwarded_for;
            proxy_set_header x-forwarded-proto https;
            proxy_set_header host $host;
            proxy_pass http://127.0.0.1;
           
            #this is will handle problem in mobile when rise protocol exception
            proxy_buffering on;
            proxy_buffer_size 8k;
            proxy_buffers 2048 8k;
        }
    }
}

                  
                               
               
               

Other Topics:
               
               
               
               
               
               
               
               

No comments:

Post a Comment