# Live Steaming with Nginx and FFMPEG

## Live Steaming with Nginx and FFMPEG

We are going to setup a complete live stream website with nginx and ffmpeg.

### Linux Server - the distribution&#x20;

I have set up on both **Ubuntu** and **Debian** and in this doc I use *Debian* as will can see with bellow information

```bash
root[1]nginx:english-pod# cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root[1]nginx:english-pod# 
```

### Install Nginx

{% hint style="warning" %}
On **Debian** (and may be others, I did not test it) we have different **complied** version of Nginx. You can search it using

```bash
apt-cache show nginx | grep nginx
```

then you will see a line link this

```bash
Depends: nginx-full (<< 1.14.2-2+deb10u3.1~) | nginx-light (<< 1.14.2-2+deb10u3.1~) | nginx-extras (<< 1.14.2-2+deb10u3.1~), nginx-full (>= 1.14.2-2+deb10u3) | nginx-light (>= 1.14.2-2+deb10u3) | nginx-extras (>= 1.14.2-2+deb10u3)
```

which simply says we have three versions for installing

* nginx-light
* nginx-full
* nginx-extras

and the deference between them is with the number of modules have been **complied** to have the binary file. For having less headache you can install `nginx-extras` so most required modules already complied into it.
{% endhint %}

{% hint style="info" %}
If you already have install Nginx, you can check the list of modules complied with Nginx using `nginx -V`&#x20;

```bash
root[1]nginx:english-pod# nginx -V
nginx version: nginx/1.14.2
built with OpenSSL 1.1.1d  10 Sep 2019
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-Cjs4TR/nginx-1.14.2=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-headers-more-filter --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-auth-pam --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-cache-purge --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-dav-ext --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-ndk --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-echo --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-fancyindex --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/nchan --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-lua --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/rtmp --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-uploadprogress --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-upstream-fair --add-dynamic-module=/build/nginx-Cjs4TR/nginx-1.14.2/debian/modules/http-subs-filter
root[1]nginx:english-pod# 
```

or you can `grep` to see **rtmp** support&#x20;

```bash
root[1]nginx:english-pod# nginx -V |& grep -o rtmp
rtmp
root[1]nginx:english-pod# 
```

{% endhint %}

We can install **Nginx** using default Debian packages or using [separate Nginx repository](http://nginx.org/en/linux_packages.html#Debian). After installing Nginx make sure it is up and running and load the IP or domain name you have to see the **Welcome to nginx!** page.

![](/files/-MW9HtG8U3q0VvP9ujhT)

### Check list of Nginx modules

Now we should check if we have **rtmp** shared library or not. First check the location

```bash
root[1]nginx:~# # nginx modules locatoin on debain and ubnutu
root[1]nginx:~# ls -1 /usr/share/nginx/
html
modules
modules-available
root[1]nginx:~# 
```

Then check the modules, here you can see I have it `ngx_rtmp_module.so` at the bottom

```bash
root[1]nginx:~# ls -1 /usr/share/nginx/modules
ndk_http_module.so
ngx_http_auth_pam_module.so
ngx_http_cache_purge_module.so
ngx_http_dav_ext_module.so
ngx_http_echo_module.so
ngx_http_fancyindex_module.so
ngx_http_geoip_module.so
ngx_http_headers_more_filter_module.so
ngx_http_image_filter_module.so
ngx_http_lua_module.so
ngx_http_perl_module.so
ngx_http_subs_filter_module.so
ngx_http_uploadprogress_module.so
ngx_http_upstream_fair_module.so
ngx_http_xslt_filter_module.so
ngx_mail_module.so
ngx_nchan_module.so
ngx_rtmp_module.so
ngx_stream_modul
```

if you did not have, check the next step

### Install rtmp modules on Debian

If you did not have the modules, `search` for it :)

```bash
root[1]nginx:~# apt-cache search  rtmp  | grep nginx
libnginx-mod-rtmp - RTMP support for Nginx
root[1]nginx:~#
```

Here is the module `libnginx-mod-rtmp` so install it

```bash
apt install libnginx-mod-rtmp -y
```

and then check the Nginx's modules location to see if we have `ngx_rtmp_module.so` or not. WE SHOULD HAVE IT.

```bash
root[1]nginx:~# ls -1 /usr/share/nginx/modules | grep rtmp
ngx_rtmp_module.so
root[1]nginx:~# 
```

[Here is the RTMP source code if wanted to see](https://github.com/arut/nginx-rtmp-module).

Here is a screenshot of mine

![](/files/-MW9N43RokTQKv2Mkmse)

{% hint style="info" %}
After you install the **ngx\_rtmp\_module.so** modules **restart** or **reload** Nginx to make sure everything is working fine

```bash
# restart
systemctl restart nginx
# check the status
systemctl status nginx

# or 
nginx -s reload
# check the status
systemctl status nginx
```

{% endhint %}

### Config `nginx.conf` file

Go to `/etc/nginx/` directory and open up `nginx.conf` file. We should add RTMP configuration to `nginx.conf` file

```bash
root[1]nginx:~# cd /etc/nginx
.
├── [4.0K]  conf.d
├── [4.0K]  modules-available
├── [4.0K]  modules-enabled
├── [4.0K]  sites-available
├── [4.0K]  sites-enabled
├── [4.0K]  snippets
├── [4.0K]  ssl
├── [1.1K]  fastcgi.conf
├── [1007]  fastcgi_params
├── [2.8K]  koi-utf
├── [2.2K]  koi-win
├── [3.9K]  mime.types
├── [1.9K]  nginx.conf
├── [ 180]  proxy_params
├── [ 636]  scgi_params
├── [ 664]  uwsgi_params
└── [3.0K]  win-utf
root[1]nginx:nginx# 
root[1]nginx:nginx# vim nginx.conf
```

Here is the configuration&#x20;

```bash
# the module we installed
# We do not have to load it explicitly 
# load_module modules/ngx_http_js_module.so;
```

and the RTMP server

```bash
# RTMP configuration
rtmp {
    server {
        listen 1935; # Listen on standard RTMP port
        chunk_size 4000;

        application show {
            live on;
            # Turn on HLS
            hls on;
            hls_path /var/www/live/hls;
            hls_fragment 3;
            hls_playlist_length 60;
            # disable consuming the stream from nginx as rtmp
            deny play all;
        }
    }
}
```

{% hint style="info" %}
Some notes

* It has its own *server* block
* Port is **1935** by default
* for each stream we have an **application** which is **show**

  ```bash
          application show {
  ```
* create this path `/var/www/live/hls` for save chuck of vidoes
* other options can be vary depending on your requirements
  {% endhint %}

{% hint style="info" %}
Our web server **root** path will be `/var/www/live`
{% endhint %}

As last step for this section, reload Nignx and make sure everything is fine.

Also here is the complete `nginx.conf` file if you want to check everything with mine.

```bash
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

# load_module modules/ngx_http_js_module.so;

events {
	worker_connections 768;
	# multi_accept on;
}

# RTMP configuration
rtmp {
    server {
        listen 1935; # Listen on standard RTMP port
        chunk_size 4000;

        application show {
            live on;
            # Turn on HLS
            hls on;
            hls_path /var/www/live/hls;
            hls_fragment 3;
            hls_playlist_length 60;
            # disable consuming the stream from nginx as rtmp
            deny play all;
        }
    }
}


http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

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

	##
	# Logging Settings
	##

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	##
	# Gzip Settings
	##

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}


#mail {
#	# See sample authentication script at:
#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#	# auth_http localhost/auth.php;
#	# pop3_capabilities "TOP" "USER";
#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#	server {
#		listen     localhost:110;
#		protocol   pop3;
#		proxy      on;
#	}
# 
#	server {
#		listen     localhost:143;
#		protocol   imap;
#		proxy      on;
#	}
#}
```

### Setting up a domain name (optional)

We can have our own domain to load the website or just using an IP address. I already have tested with IP address and preferred to have a domain name so I used **live.shakiba.net**

### **Setting up SSL/TLS and HTTPS for domain (optional)**

We do not have to do so, but again I preferred to have it. You can use any **CDN** provider and most of them support **Free SSL** using **Lets Encrypt** to issue 90 days certificate. So mine endpoint will be **<https://live.shakiba.net>**

### Configure `live.shakiba.net` file in `sites-available/`

Since my chosen domain is *live.shakiba.net* I will use this name, you have your own. You can see bellow I have the file

```bash
root[1]nginx:sites-available# pwd
/etc/nginx/sites-available
root[1]nginx:sites-available# ll
total 32
-rw-r--r-- 1 root root 2412 Aug 24  2020 default
-rw-r--r-- 1 root root  142 Feb 18 10:41 examp1e.ir
-rw-r--r-- 1 root root 1221 Mar  8 13:27 homepc.shakiba.net
-rw-r--r-- 1 root root 4066 Mar 19 11:20 live.shakiba.net
-rw-r--r-- 1 root root 2942 Feb  6 11:36 media.shakiba.net
-rw-r--r-- 1 root root  617 Mar 19 10:42 msa.shakiba.net
-rw-r--r-- 1 root root 1086 Feb 21 15:37 redcursor.ir
-rw-r--r-- 1 root root  887 Mar  8 12:02 shakiba.net
root[1]nginx:sites-available# 
```

**basic configuration** to check the load of the domain

```bash
server {
    listen 443;
    listen [::]:443;
    
	  server_name live.shakiba.net;
    index index.html;
    root /var/www/live;
    
    location / {
        try_files $uri $uri/ =404;
    }
}
server {
    listen 80;
    listen [::]:80;
    server_name live.shakiba.net;
    return 301 https://$host$request_uri;
}
```

**root directory** we have set up is `/var/www/live` so make sure you have it and add a sample **index.html** to the location which means we will have `/var/www/live/index.html`

**reload** or **restart** Ningx the load your own domain name or IP address ir you did not have domain name and have set it up on your **localhost**

Here is a screenshot of mine which I made it fancy, of course you do not have to make it fancy.

![](/files/-MW9X-2szTUqpTshFu-c)

*the reset will be added soon*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.shakiba.net/web-server/nginx/live-steaming-with-nginx-and-ffmpeg.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
