Server de Streaming 
=====================
Toata lumea stie sa faca streaming pe Twitch sau Youtube insa aici vom descrie situatia in care vrei sa faci streaming pe un server privat.
Este util in situatia in care vreti sa transmiteti un meci de fotbal de exemplu de pe Voyo si pe youtube este interzis. De asemeni solutia este foarte securizata, streamul se va putea viziona pe serverul
unde aveti pluginul pt stream de catre prieteni care se vor inregistra, voi explica mecanismul mai jos.
Pe calculatorul cu windows veti folosi arhicunoscutul OBS prin intermediul caruia veti face stream catre un custom server.
In Settings/Stream veti alege Service Custom unde veti pune adresa serverului catre care faceti stream:
rtmps://stream.example.com:4443/live
Dedesubt trebuie sa declarati un stremkey prin intermediul caruia puteti avea control, acel streamkey se va declara si in playerul in care se va face vizionarea.
Mai intai de toate aveti nevoie de un server cu linux unde aveti nevoie de 2 domenii:
-stream.example.com
-player.example.com
Ambele domenii vor pointa in DNS catre acelasi IP public al VPS-ului.
Acest server cu linux este recomandat sa fie un VPS in cloud care are nevoie de un bandwidth foarte bun, recomandat macar 1 gbps up/down daca se vor conecta mai multi prieteni.
Instalati prima data docker:
$ apt update && apt upgrade -y
$ apt install docker.io -y
Daca pe masina aveti ip de retea atunci se forwardeaza:
TCP 443
TCP 4443
Eu am pus totul cu root, recomandat este sa se foloseasca totusi un user separat.
Se da allow din firewall pe masina la aceste porturi (iptables, ufw, depinde ce ai).
Exemplu basic iptables pt custom ports exista
aici
Se face folderul /root/rtmp unde aici se va intampla tot ce explic in acest tutorial!
In acest folder vom porni urmatoarele containere:
-nginx cu pluginul RTMP pt stream
-php
-mysql pt baza de date
-haproxy pt a permite sa faceti broadcast securizat de la OBS-ul vostru catre acest server.
Le vom lua pe fiecare in parte, nu e chiar simplu setupul:
Mentionez faptul ca ambele domenii vor avea nevoie de certificate nginx, nu mai acopar aici aceast aspect, fisierele generate trebuie folosite in haproxy si in nginx.
Pt nginx trebuie 2 certificate pt stream.example.com si pt player.example.com sau unul singur wildcard pt *.example.com (asta daca aveti acest domeniu).
HAProxy
Se creeaza fisierul starthaproxy.sh cu care se porneste containerul:
docker run -itd --name haproxy --memory="80m" --restart=always \
--network=host --dns 1.1.1.1 \
-v /root/rtmp/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg \
-v /root/rtmp/errors:/etc/haproxy/errors \
-v /opt:/etc/ssl \
haproxy:2.6
Containerul are nevoie de niste fisiere cu erori posibile, luati
acest zip si dezarhivati-l in /root/rtmp.
De asemeni este nevoie de fisierul de configurare haproxy.cfg
Observati aici adresa locala a serverului si anume 172.27.72.2:1935. trebuie schimbat ip-ul cu ip-ul serverului in absolut toate fisierele din acest tutorial!!!!!!!!!
De asemeni exista si un fisier pem, acel fisier este certificat bundle stream.example.com care se obtine din cele doua fisiere certificat generate cu LetEncrypt
Se pun efectiv unul sub altul fisierele fullchain si privkey intr-un fisier nou: sigmelu.pem
Nginx
Containerul cu nginx trebuie compilat cu docker build folosind Dockerfile:
Eu in acest container pe langa RTMP am instalat mai multe module nginx printre care si webdav si image-filter-watermark, se pot scoate f usor insa nu incurca, webdav cel putin eeste foarte foartte util.
Creati imaginea cu urmatoarea comanda:
docker build -t nginxrtmp:1 .
Sa presupunem ca imaginea creata folosing acest Dockerfile este nginxrtmp:1, creati startnginx.sh:
docker run -itd --name rtmptest \
-v /etc/localtime:/etc/localtime:ro \
-v /root/rtmp/nginx:/etc/nginx \
-v /root/rtmp/html:/var/www/html \
-v /opt:/etc/ssl \
--network=host \
nginxrtmp:1
Pt ca acest container sa porneasca si sa functioneze corespunzator veti avea nevoie si de o structura de subfoldere in /root/rtmp/nginx: conf.d, parole.
De asemeni /root/rtmp/html/unde practic este home directory-ul nginx-ului.
Iata fisierele de configrare ale serverului si ale vhostului cu playerul:
-nginx.conf (se afla in /root/rtmp/nginx):
-default.conf (se afla in /root/rtmp/nginx/conf.d):
-player.conf (se afla in /root/rtmp/nginx/conf.d):
-iplist.txt (se afla in /root/rtmp/html):
Acest fisier asigura securiiitatea streamului, clientii care se conecteaza sa vizioneze streamul trebuie sa aiba IP-ul declarat in acest fisier.
Contentul fisierului se genereaza cu ajutorul unui mecanism systemd dupa cum urmeaza:
Se creeaza in /etc/systemd/system doua fisiere:
1. iplist.path:
[Unit]
Description=Watch /root/rtmp/html/iplist.txt for changes
[Path]
PathModified=/root/rtmp/html/iplist.txt
[Install]
WantedBy=multi-user.target
2. iplist.service:
[Unit]
Description=Restart-iplist
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/docker exec -t rtmptest /usr/local/sbin/nginx -s reload
[Install]
RequiredBy=iplist.path
$ systemctl restart iplist.{path,service}
$ systemctl status iplist.{path,service}
Dupa ce un user se va loga, scriptul php va updata /root/rtmp/html/iplist.txt si serviciul asta iplist(target si service) va vedea ca s-a modifica si ca atare va da reload la nginx.
Valabil si cand un user se va deloga sau daca va inchide browserul si la un moment dat ii va da timeout, de asemeni IP-ul sau se va sterge automat.
Fisierul iplist.txt trebuie sa aiba chmod 777.
Se va crea si un subfolder si anume control unde este un panel de administrare de unde se confirma useri, se sterg etc.
Sursa completa a playerului va fi atasata la sfarsitul tutorialului.
PHP
Containerul cu php trebuie de asemeni compilat cu docker build folosind Dockerfile:
Creati imaginea cu urmatoarea comanda:
docker build -t php-fpm-websocket .
Porniti containerul cu urmatorul fisier startphp.sh:
docker run -itd --name php \
-v /root/rtmp/html:/var/www/html \
-v /root/rtmp/php.ini:/usr/local/etc/php/php.ini \
-v /root/rtmp/fpm:/usr/local/etc/php-fpm.d \
-v /etc/localtime:/etc/localtime:ro \
--privileged --network=host \
php-fpm-websocket
# Wait for the container to start
sleep 5
# Start the WebSocket server inside the running container
docker exec php /usr/local/bin/php /var/www/html/live/chat_server.php &
Se vede clar ca se foloseste /root/rtmp/fpm pt a suprascrie ce este in container in /usr/local/etc/php-fpm.d \
Scopul pt care am facut treaba asta este ca am vrut ca php-fpm sa porneasca pe portul 9001 si nu 9000, treaba asta se specifica in www.conf pe care trebuie sa il creati in folderul fpm:
S-ar fi putut face mai elegant direct din Dockerfile insa nu am testat, ca atare aveti nevoie de www.conf:
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9001
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
Pt serverul de chat va trebui initializata componenta cboden/ratchet:
$ docker exec -it php sh
/var/www/html # cd live
/var/www/html/live # composer require cboden/ratchet
Comanda asta creeaza subfolderul vendor cu tot ce trebuie si de asemeni in folderul principal apar composer.json si composer.lock.
Mysql
Exista
aici un tutorial cu un manager de parole care foloseste exact acelasi container mysql 5.7, care se porneste asa:
docker run -itd --name mysql57 --network=marianet --ip 172.19.10.10 \
-e MYSQL_ROOT_PASSWORD=parolaroot \
-e MYSQL_DATABASE=vaultwarden \
-e MYSQL_USER=iuzar \
-e MYSQL_PASSWORD=parolaiuzar \
--restart=always \
-v /root/bitwardenmysql/mysql:/var/lib/mysql \
-v /etc/localtime:/etc/localtime:ro \
mysql:5.7
Modificati parolele celor 2 useri, oricum se va folosi userul root
Se creeaza baza de date rtmp in care se pun doua tabele:
In momentul in care baza de date este pornita si nginx si php sunt configurate corect si de asemeni pornite corect, prin intermediul HAProxy puteti porni streamul cu OBS catre stream.example.com cu URL:
rtmps://stream.example.com:4443/live.
Sus cand am discutat de firewall nu am specificat nimic de portul 1935 care este inchis, broadcast cu OBS se face secure, cu certificat.
Streamul din OBS se face cu RTMP H264 insa serverul nginx il preia si il transpune in HLS. In configul de nginx in sectiunea rtmp se poate observa hls. Playerul web se conecteaza la HLS, streamul de fapt este HLS.
Exista si DASH, sunt mai multe variante mai moderne care permit sa faci stream cu codecuri mai noi si mai eficiente de ex av1 insa se reduce f mult si probabilitatea ca cel care se uita sa nu aiba cu ce sa decodeze.
Aceasta este o solutie folosita de ani de zile si chiar daca este putin invechita inca se descurca excelent.
Asadar, aveti
aici arhiva care contine folderul live, deci trebuie sa fie dupa dezarhivare /root/rtmp/html/live. Acesta este playerul care in browser raspunde la https://player.example.com.
Va logati cu admin si aveti si un panel de administrare. Linkul este protejat cu htpasswd, pt asta generati .htpasswd in /root/rtmp/nginx/parole/control
htpasswd -c /root/rtmp/nginx/parole/control/.htpasswd admin
Dupa ce puneti fisierul, va functiona si panelul de administrare.
De aici puteti activa/dezactiva un user, puteti sterge sesiunile unui user sau il puteti sterge de tot. Reset password nu am facut desi nu ar fi f complicat.
Revenind la player, o sa vedeti URL-ul care by default are linkul catre serverul nginx:
https://stream.example.com/hls/test.m3u8. test este numele streamkey-ului pe care il setati in OBS, ca sa stiti ce e cu el. Este de fapt un playlist care serveste fisierele .ts care se creeaza in subfolderul hls.
Playerul este simplist si se conecteaza la nginx, care nginx preia secure streamul RTMP(s) din obs, il transforma in hls si il serveste mai departe catre player. Nu este real time, like I said, utilitatea acestei solutii este sa fie folosit de ex pt o transmisie sportiva. Delay-ul este in jur de 20 s. Calitatea este in functie de ce setari folositi la OBS: Am explicat mai sus ca in OBS la stream faceti catre server custom, iar la Output eu de ex folosesc NVIDIA NVENC H.264, Output 1920x1080, Rate Control VBR, Bitrate 4000 kbps, Max Bitrate 9000 kbps, Preset P5: Slow, Tuning Ultra Low Latency, Multipass Mode Two Passes(FUll Resolution), Profile High. Recomand sa faceti stream cu 60 fps, nu cu 30, conteaza f mult.
Nu conteaza ce bandwidth aveti acasa unde ruleaza OBS pt ca trimiteti streamul o data catre nginx, banda conteaza la server (upload). Daca se conecteaza sa zicem 10 insi, serverul face upload x10 si la un bitrate mediu de 7000kbps va fi x10.
Exista si o caseta de chat, veti putea trimite mesaje real time tuturor celor care sunt logati, nu are chat privat.
Dpdv security, daca setati corect serviciul systemd iplist, numai cine este logat poate viziona streamul. URL-ul este la vedere, nu am de ce sa il ascund pt ca se vede cat se poate de clar in consola browserului.
Streamul nu se poate monta in niciun player, are o protectie in acest sens, este privat, repet, daca serverul este pe un VPS se poate folosi lejer. Dati acces din panelul de administrare numai pretenilor, orice user nu se poate loga decat o data, se permite numai o singura sesiune, deci exclus ca va da parola altcuiva sa se conecteze la stream. Playerul are signup insa contul se creeaza in pending, numai voi cu admin il puteti confirma.
Aceasta este o solutie privata, utila dupa cum spuneam pt o transmisiune sportiva care nu se poate viziona gratis nicaieri. Luati abonament pe o luna, dati drumul in browser si stream-uiti mai departe catre serverul privat. O mica paranteza, am observat ca la multe platforme de ex si la Voyo, nu puteti captura streamul in OBS, se vede ecran negru. Solutia este sa dezactivati decodarea hw in browser, se poate face si cu chrome si cu firefox si de abia dupa aia puteti captura imagine plus sunet. Limitati-va la un numar mic de oameni care se vor uita, prieteni, familie, max 10-15 insi (fiecare cu contul lui)
Repet, fiecare isi face cont si trebuie individual sa le confirmati la fiecare, am incercat sa creez un environment cat mai secure.
Enjoy!