Skip to content

Instantly share code, notes, and snippets.

Last active December 26, 2022 19:30
Show Gist options
  • Star 71 You must be signed in to star a gist
  • Fork 37 You must be signed in to fork a gist
  • Save mikhailov/3174601 to your computer and use it in GitHub Desktop.
Save mikhailov/3174601 to your computer and use it in GitHub Desktop.
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 #=>
Copy link

Hi, thank you very much for this beautiful work, i was wondering if there is a way to limit the video by ip just like google and other sites does. thank you

Copy link

iKalin commented Jul 4, 2016

wich version of ruby you use?

Copy link

imfa1se commented Dec 26, 2018

Anyone about to offer some assistance with this thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment