> For the complete documentation index, see [llms.txt](https://docs.shakiba.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.shakiba.net/web-server/nginx/live-steaming-with-nginx-and-ffmpeg.md).

# 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*
