Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Nginx + secure pseudo-streaming
# Nginx can serve FLV/MP4 files by pseudo-streaming way without any specific media-server software.
# To do the custom build we use 2 modules: --with-http_secure_link_module --with-http_flv_module
# This module "secure-link" helps you to protect links from stealing away.
# NOTE: see more details at coderwall:
cd /usr/src
tar xzvf ./nginx-1.5.13.tar.gz && rm -f ./nginx-1.5.13.tar.gz
tar xzvf pcre-8.32.tar.gz && rm -f ./pcre-8.32.tar.gz
tar xzvf openssl-1.0.1g.tar.gz && rm -f openssl-1.0.1g.tar.gz
cd nginx-1.5.13 && ./configure --prefix=/opt/nginx --with-pcre=/usr/src/pcre-8.32 --with-openssl-opt=no-krb5 --with-openssl=/usr/src/openssl-1.0.1g --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --with-http_stub_status_module --with-http_secure_link_module --with-http_flv_module --with-http_mp4_module
make && make install
$ cd /opt/nginx/html
$ echo "<cross-domain-policy>
<allow-access-from domain='*' />
</cross-domain-policy>" > crossdomain.xml
$ echo "User-Agent: *
Disallow: /" > robots.txt
# Nginx uses the protected links that build with md5 of YOUR_SECRET_PASSWORD_HERE, URI and Unix timestamp
user app;
worker_processes 2;
timer_resolution 100ms;
error_log logs/error.log;
pid logs/;
events {
worker_connections 1024;
http {
include mime.types;
default_type application/octet-stream;
access_log off;
sendfile on;
server_tokens off;
keepalive_timeout 65;
ssl_certificate /opt/nginx/ssl_certs/server.crt;
ssl_certificate_key /opt/nginx/ssl_certs/server.key;
ssl_session_timeout 15m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
server {
ssl on;
listen 443 default ssl;
access_log logs/access.log;
location /video/ {
rewrite /video/([a-zA-Z0-9_\-]*)/([0-9]*)/(.*)\.flv$ /flv/$3.flv?st=$1&e=$2;
location /flv/ {
secure_link $arg_st,$arg_e;
secure_link_md5 YOUR_SECRET_PASSWORD_HERE$arg_e$uri;
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 403; }
root /mnt/your_directory;
add_header Cache-Control 'private, max-age=0, must-revalidate';
add_header Strict-Transport-Security "max-age=16070400; includeSubdomains";
add_header X-Frame-Options DENY;
location =/ {
root /404.html;
location = /50x.html {
root html;
location ~ \.(php|html)$ {
deny all;
require 'rubygems'
require 'activesupport'
require 'digest/md5'
class Signature
PASSWORD = 'YOUR_SECRET_PASSWORD_HERE' # use this password for nginx directive "secure_link_md5"
DIR = 'flv' # the internal nginx location to access to media files
SERVER_NAME = '' # nginx listen address and port
attr_reader :expiration_time, :file_name, :md5
def initialize(file_name)
@expiration_time = ( + 2.hours).to_i
@file_name = file_name
def generate
# nginx secured URL to access to media files, "video" is the location, not real directory on filesystem
def md5_calculate
s = "#{PASSWORD}#{@expiration_time}/#{DIR}/#{@file_name}"
a = Base64.encode64(Digest::MD5.digest(s))
@md5 ="+/", "-_").sub('==', '').chomp
url ='video1.flv')
puts url.expiration_time #=> 1326559618
puts url.md5 #=> HLz1px_YzSNcbcaskzA6nQ
puts url.generate #=>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment