This example is part of this article.
This is an example for an HLS delivery with basic security. Nginx compiled with nginx-rtmp-module & secure-link is used as media server. Features:
- Domain filtering
- Referrer filtering
- Embed buster
- Session token for playlist, segments and AES keys
- AES encryption
- HTTPS only
Throughout this example the host is assumed to be example.com
.
if you want to use this configurations, be sure to replace all instances of example.com
with your domain.
# install deps (Ubuntu)
sudo apt-get install -y build-essential libpcre3 libpcre3-dev libssl-dev
wget http://nginx.org/download/nginx-1.10.1.tar.gz
tar -xf nginx-1.10.1.tar.gz
cd nginx-1.10.1
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module --with-http_secure_link_module
make -j
sudo make install
# nginx is now installed in /usr/local/nginx
In order to push video to nginx i'm going to use ffmpeg which well supports RTMP as its output.
I'm going to create an I frame
roughly every 2 seconds which will allow nginx to achieve the 4s segment target.
For simplicity i'll be using a static mp4 file and ingest it in infinite loop.
ffmpeg -hide_banner \
-stream_loop -1 \
-re -i test-video.mp4 \
-c:a aac -c:v h264 -g 48 \
-f flv rtmp://localhost:1935/show/live
I'm using live
as the stream name, the output hls will carry that same name - e.g. live.m3u8
.
The session token is based on this format (note the spaces):
MD5("EXPIREY_DATE_IN_SECONDS CLIENT_IP_ADDRESS SECRET")
here are several examples of generating the token:
BASH
get_customer_url() {
local IP=${1:-127.0.0.1}
local SECRET=${2:-VERY_COOL_SECRET}
local EXPIRES="$(date -d "today + 30 minutes" +%s)";
local token="$(echo -n "${EXPIRES} ${IP} ${SECRET}" | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)"
echo "https://example.com/video/hls/${token}/${EXPIRES}/live.m3u8"
}
get_customer_url 10.20.1.55 "uigfp(@#tfpIUDGPFiouGDF"
Node.JS (Javascript)
var crypto = require('crypto');
function generateSecurePathHash(expires, client_ip, secret) {
if (!expires || !client_ip || !secret) throw new Error('Must provide all token components');
var input = expires + ' ' + client_ip + ' ' + secret;
var binaryHash = crypto.createHash('md5').update(input).digest();
var base64Value = new Buffer(binaryHash).toString('base64');
return base64Value.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}
function getStreamUrl(ip, secret) {
const expiresTimestamp = new Date(Date.now() + (1000 * 60 * 30)).getTime();
const expires = String(Math.round(expiresTimestamp / 1000));
const token = generateSecurePathHash(expires, ip, secret);
return `https://example.com/video/hls/${token}/${expires}/live.m3u8`;
}
getStreamUrl('127.0.0.1', 'uigfp(@#tfpIUDGPFiouGDF');
// https://example.com/video/hls/LdS-kcC-JGVHGNTFlX-6Sw/1526373776/live.m3u8
Works ok on CentOS7.
The way work on CentOS and bash script to generate link:
On Script bash:
#!/bin/bash
get_customer_url() {
local IP=${1:-127.0.0.1}
local SECRET=${2:-PASSWORD123}
local EXPIRES="$(date -d "today + 30 minutes" +%s)";
local token="$(echo -n "${EXPIRES} ${IP} ${SECRET}" | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)"
echo "https://example.com/video/hls/${token}/${EXPIRES}/live.m3u8"
}
get_customer_url 10.20.1.55 PASSWORD123
------------------------------------- END BASH FILE -------------------------------------------------------
10.20.1.55 you change to your IP on internet. Whatsmyip will tell you the value. Is not the IP server or where index.html will be hosted, is the IP from your computer test (will browser to the index.html page).
Probably you don't need to change local SECRET=${2:-VERY_COOL_SECRET} because is a parameter, but to not make visual confusion, change.
On nginx.conf,
secure_link_md5 "$secure_link_expires $remote_addr VERY_COOL_SECRET";
change to
secure_link_md5 "$secure_link_expires $remote_addr PASSWORD123";
------------------------------------- END OF NGINX.CONF ------------------------------------------
Now you have the index.html on /mnt. Remember, the CORS protec your page from be used from other domain/ip.
Don't use VLC and others to test, will always break.
On Index.html change the line of src video to one generated on bash script from begin.
-------------------------------------- END index.html --------------------------------------------------
Notes: If you use curl or firefox console and get 403 error, is because URL, IP or Secret (password) is wrong. The password insert against IP on bash and nginx.conf always must be equal, is the verification text to verify if is authentic.