Canlı yayın altyapısı kurmak isteyip de Twitch veya YouTube’a bağımlı kalmak istemeyenler için Nginx’in RTMP modülü gerçek bir nimet. Kendi streaming sunucunu kurmak hem maliyet açısından hem de veri kontrolü açısından büyük avantaj sağlıyor. Bu yazıda sıfırdan bir canlı yayın sunucusu kurarak, HLS ve DASH çıktısı üretmeyi, OBS ile test etmeyi ve production ortamında güvenli hale getirmeyi ele alacağız.
RTMP Nedir ve Neden Nginx?
RTMP (Real-Time Messaging Protocol), Adobe tarafından geliştirilen ve düşük gecikme süresiyle video/ses akışı için tasarlanmış bir protokol. Her ne kadar HTTP tabanlı protokoller (HLS, DASH) günümüzde daha yaygın olsa da, yayıncıdan sunucuya veri göndermek (ingest) için RTMP hala endüstri standardı olmaya devam ediyor.
Nginx’in nginx-rtmp-module eklentisi, Nginx’i tam anlamıyla bir medya sunucusuna dönüştürüyor. FFmpeg ile birleştiğinde şunları yapabiliyorsun:
- Gelen RTMP akışını alıp HLS segmentlerine dönüştürmek
- Birden fazla kalite seviyesi (adaptive bitrate) üretmek
- Yayını kayıt altına almak
- Aynı anda birden fazla platforma iletmek (restream)
- Kimlik doğrulama ile yayını korumak
Sistem Gereksinimleri ve Ön Hazırlık
Bu rehberde Ubuntu 22.04 LTS kullanıyoruz. Minimum donanım olarak 2 CPU, 4 GB RAM ve iyi bir ağ bant genişliği öneriyorum. Yayın kalitesine göre bu gereksinimler değişiyor, 1080p 30fps için 6-8 Mbps upload kapasitesi yeterli.
Önce sistemi güncelleyelim ve gerekli bağımlılıkları yükleyelim:
sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential libpcre3 libpcre3-dev
libssl-dev libgd-dev git ffmpeg
libxslt-dev libgeoip-dev
zlib1g-dev
FFmpeg kurulumunu doğrulayalım:
ffmpeg -version
# ffmpeg version 4.4.2 veya üzeri çıkmalı
Nginx’i RTMP Modülü ile Derleme
Ubuntu depolarındaki hazır Nginx paketi RTMP modülünü içermiyor. Bu yüzden Nginx’i kaynak koddan derleyeceğiz. Evet, biraz uzun bir yol ama bir kez kurulunca sorunsuz çalışıyor.
# Nginx kaynak kodunu indir
cd /tmp
NGINX_VERSION=1.24.0
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -xzf nginx-${NGINX_VERSION}.tar.gz
# RTMP modülünü GitHub'dan çek
git clone https://github.com/arut/nginx-rtmp-module.git
# Derleme dizinine gir
cd nginx-${NGINX_VERSION}
# Konfigürasyon ve derleme
./configure
--prefix=/etc/nginx
--sbin-path=/usr/sbin/nginx
--modules-path=/usr/lib64/nginx/modules
--conf-path=/etc/nginx/nginx.conf
--error-log-path=/var/log/nginx/error.log
--http-log-path=/var/log/nginx/access.log
--pid-path=/var/run/nginx.pid
--with-http_ssl_module
--with-http_v2_module
--with-http_gzip_static_module
--with-http_stub_status_module
--with-http_realip_module
--with-threads
--with-file-aio
--add-module=../nginx-rtmp-module
make -j$(nproc)
sudo make install
Derleme birkaç dakika sürebilir. Hata alırsan büyük ihtimalle eksik bir kütüphane var, hata mesajına göre ilgili -dev paketini yükle.
Nginx’i systemd servisi olarak tanımlayalım:
sudo cat > /etc/systemd/system/nginx.service << 'EOF'
[Unit]
Description=Nginx HTTP Server with RTMP Module
After=network.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable nginx
Ana Nginx Konfigürasyonu
Şimdi işin en kritik kısmına geldik. /etc/nginx/nginx.conf dosyasını aşağıdaki gibi yapılandırıyoruz:
worker_processes auto;
events {
worker_connections 1024;
}
# RTMP bloğu HTTP bloğunun dışında tanımlanır
rtmp {
server {
listen 1935;
chunk_size 4096;
allow publish all;
application live {
live on;
record off;
# HLS çıktısı
hls on;
hls_path /var/www/hls;
hls_fragment 3;
hls_playlist_length 60;
# DASH çıktısı
dash on;
dash_path /var/www/dash;
dash_fragment 3;
# Yayın başladığında ve bittiğinde FFmpeg ile transcode
exec_push ffmpeg -i rtmp://localhost/live/$name
-c:v libx264 -b:v 1024k -vf scale=854:480 -c:a aac -b:a 128k
-f flv rtmp://localhost/hls480/$name
-c:v libx264 -b:v 2500k -vf scale=1280:720 -c:a aac -b:a 192k
-f flv rtmp://localhost/hls720/$name 2>>/var/log/nginx/ffmpeg.log;
}
application hls480 {
live on;
hls on;
hls_path /var/www/hls/480p;
hls_fragment 3;
hls_playlist_length 60;
deny play all;
}
application hls720 {
live on;
hls on;
hls_path /var/www/hls/720p;
hls_fragment 3;
hls_playlist_length 60;
deny play all;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name your-domain.com;
# HLS içeriği için
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
# DASH içeriği için
location /dash {
types {
application/dash+xml mpd;
}
root /var/www;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
# İstatistik sayfası
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root /tmp/nginx-rtmp-module;
}
}
}
HLS ve DASH dizinlerini oluşturalım:
sudo mkdir -p /var/www/hls/{480p,720p}
sudo mkdir -p /var/www/dash
sudo chown -R www-data:www-data /var/www/
sudo chmod -R 755 /var/www/
# Nginx'i başlat
sudo systemctl start nginx
sudo systemctl status nginx
Stream Key ile Güvenlik
Herkese açık bir RTMP sunucusu istemiyorsun. on_publish hook’unu kullanarak stream key doğrulaması ekleyelim.
Önce doğrulama için basit bir PHP/Python script’i oluşturalım. Ben burada Python Flask kullanıyorum:
# /opt/stream-auth/auth.py
from flask import Flask, request, abort
import os
app = Flask(__name__)
# Gerçek ortamda bunu bir veritabanından veya env değişkeninden oku
VALID_STREAM_KEYS = {
"obs-yayin-1": "kullanici1",
"mobil-yayin-abc": "kullanici2",
}
@app.route('/auth', methods=['POST'])
def authenticate():
stream_key = request.form.get('name', '')
client_ip = request.remote_addr
if stream_key in VALID_STREAM_KEYS:
user = VALID_STREAM_KEYS[stream_key]
print(f"[AUTH OK] User: {user}, Key: {stream_key}, IP: {client_ip}")
return '', 200
else:
print(f"[AUTH FAIL] Key: {stream_key}, IP: {client_ip}")
abort(403)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8090)
pip3 install flask
# Servisi çalıştır
python3 /opt/stream-auth/auth.py &
# Nginx RTMP konfigürasyonuna ekle
# application live bloğuna:
# on_publish http://127.0.0.1:8090/auth;
RTMP konfigürasyonundaki application live bloğuna bu satırı eklediğinde, yayıncı bağlandığında Nginx auth servisine istek atacak. 403 dönerse bağlantıyı reddedecek.
OBS ile Test
Kurulum hazır, şimdi OBS Studio ile test edelim.
OBS’de ayarlar menüsüne gir, Stream sekmesine geç:
- Service: Custom
- Server:
rtmp://sunucu-ip/live - Stream Key:
obs-yayin-1(auth script’indeki key)
Yayını başlat ve sunucuda şunu kontrol et:
# HLS segmentlerinin oluştuğunu doğrula
ls -la /var/www/hls/
# index.m3u8 ve .ts dosyaları görünmeli
# RTMP bağlantılarını izle
tail -f /var/log/nginx/error.log
# FFmpeg transcoding logunu izle
tail -f /var/log/nginx/ffmpeg.log
# Aktif stream sayısını kontrol et
curl -s http://localhost/stat | grep -o '<active>[^<]*</active>'
Tarayıcıda test için VLC kullanabilirsin ya da direkt http://sunucu-ip/hls/obs-yayin-1.m3u8 adresini aç.
Web Player Entegrasyonu
Sunucu hazır ama kullanıcıların tarayıcıdan izleyebilmesi için bir player gerekiyor. Video.js veya HLS.js ile basit bir sayfa hazırlayalım:
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Canlı Yayın</title>
<link href="https://vjs.zencdn.net/8.0.4/video-js.css" rel="stylesheet" />
<style>
body { background: #1a1a1a; display: flex; justify-content: center; padding: 40px; }
.video-container { width: 100%; max-width: 900px; }
</style>
</head>
<body>
<div class="video-container">
<video id="player" class="video-js vjs-default-skin vjs-big-play-centered"
controls autoplay width="100%" height="500">
<source src="/hls/STREAM_KEY.m3u8" type="application/x-mpegURL">
</video>
</div>
<script src="https://vjs.zencdn.net/8.0.4/video.min.js"></script>
<script>
var player = videojs('player', {
liveui: true,
fluid: true
});
</script>
</body>
</html>
Bu dosyayı /var/www/html/index.html olarak kaydet, STREAM_KEY kısmını gerçek key ile değiştir.
SSL/TLS ile Güvenli Bağlantı
Production ortamında HTTP üzerinden HLS sunmak istemezsin. Let’s Encrypt ile SSL ekleyelim:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d your-domain.com
# Otomatik yenileme kontrolü
sudo certbot renew --dry-run
Certbot Nginx konfigürasyonunu otomatik güncelleyecek. Ama RTMP portu (1935) için SSL (RTMPS) eklemek istersen Nginx bunu doğrudan desteklemiyor. Bu durumda stunnel kullanabilirsin:
sudo apt install stunnel4 -y
# /etc/stunnel/stunnel.conf
sudo cat > /etc/stunnel/stunnel.conf << 'EOF'
[rtmps]
accept = 443
connect = 1935
cert = /etc/letsencrypt/live/your-domain.com/fullchain.pem
key = /etc/letsencrypt/live/your-domain.com/privkey.pem
EOF
sudo systemctl enable stunnel4
sudo systemctl start stunnel4
Artık OBS’de rtmps://your-domain.com/live adresini kullanabilirsin.
Yayın Kaydı ve VOD Sistemi
Canlı yayınları kaydetmek için RTMP modülünün record özelliğini kullanabiliriz:
application live {
live on;
# Kayıt ayarları
record all;
record_path /var/recordings;
record_suffix -%Y%m%d-%H%M%S.flv;
record_unique on;
record_interval 1h; # Saatlik parçalara böl
# Kayıt tamamlandığında FFmpeg ile MP4'e çevir
exec_record_done ffmpeg -i $path
-c:v copy -c:a copy
/var/www/vod/$basename.mp4;
}
sudo mkdir -p /var/recordings /var/www/vod
sudo chown www-data:www-data /var/recordings /var/www/vod
# VOD için Nginx location ekle
# HTTP server bloğuna:
# location /vod {
# root /var/www;
# mp4;
# mp4_buffer_size 1m;
# mp4_max_buffer_size 5m;
# }
Monitoring ve İzleme
Nginx RTMP modülü dahili bir istatistik sayfası sunuyor ama bunu Prometheus ile entegre etmek daha pratik:
# nginx-rtmp-exporter kur
wget https://github.com/beaufour/rtmp-exporter/releases/latest/download/rtmp_exporter_linux_amd64.tar.gz
tar xzf rtmp_exporter_linux_amd64.tar.gz
sudo mv rtmp_exporter /usr/local/bin/
# Servis oluştur
sudo cat > /etc/systemd/system/rtmp-exporter.service << 'EOF'
[Unit]
Description=RTMP Prometheus Exporter
After=network.target
[Service]
ExecStart=/usr/local/bin/rtmp_exporter
--rtmp.scrape-uri=http://localhost/stat
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now rtmp-exporter
Basit bir izleme script’i ile aktif yayınları takip edebilirsin:
#!/bin/bash
# /usr/local/bin/stream-monitor.sh
STAT_URL="http://localhost/stat"
LOG_FILE="/var/log/stream-monitor.log"
while true; do
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# Aktif stream sayısını çek
ACTIVE=$(curl -s $STAT_URL | grep -c '<active>1</active>' 2>/dev/null || echo "0")
# Toplam bant genişliği
BANDWIDTH=$(curl -s $STAT_URL | grep -o '<bw_in>[0-9]*</bw_in>' |
grep -o '[0-9]*' | awk '{sum+=$1} END {print sum/1024/1024 " Mbps"}')
echo "[$TIMESTAMP] Aktif yayınlar: $ACTIVE | Bant genişliği: $BANDWIDTH" >> $LOG_FILE
# Disk kullanımını kontrol et
DISK_USAGE=$(df /var/www/hls | awk 'NR==2{print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 85 ]; then
echo "[$TIMESTAMP] UYARI: Disk dolulugu %$DISK_USAGE" >> $LOG_FILE
# Eski segmentleri temizle
find /var/www/hls -name "*.ts" -mmin +30 -delete
fi
sleep 60
done
sudo chmod +x /usr/local/bin/stream-monitor.sh
# Tmux veya screen içinde çalıştır ya da systemd servisi yap
Sık Karşılaşılan Sorunlar
Yayın bağlanıyor ama HLS dosyaları oluşmuyor: FFmpeg yolunu kontrol et. which ffmpeg komutunun çıktısını Nginx konfigürasyonundaki exec_push yoluna yaz. Ayrıca /var/log/nginx/ffmpeg.log dosyasını mutlaka incele.
Gecikme çok fazla: hls_fragment değerini 1-2 saniyeye düşür ve hls_playlist_length değerini de azalt. Ama çok düşürürsen buffering sorunu yaşarsın.
Port 1935 erişilemiyor:
sudo ufw allow 1935/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# AWS, GCP gibi bulut ortamlarında güvenlik grubu/firewall kurallarını da güncelle
Çok sayıda bağlantıda performans düşüyor: worker_connections değerini artır ve worker_processes değerini CPU sayısına eşitle. Ayrıca HLS dosyalarını RAM disk üzerinde tutmak gecikmeyi dramatik biçimde azaltıyor:
# tmpfs ile RAM disk
sudo mount -t tmpfs -o size=2G tmpfs /var/www/hls
# /etc/fstab'a ekle kalıcı olması için:
# tmpfs /var/www/hls tmpfs defaults,size=2G 0 0
Restream: Aynı Anda Birden Fazla Platforma Yayın
Kendi sunucuna gelen yayını aynı anda Twitch ve YouTube’a da iletebilirsin:
application live {
live on;
# Twitch'e ilet
push rtmp://live.twitch.tv/app/TWITCH_STREAM_KEY;
# YouTube'a ilet
push rtmp://a.rtmp.youtube.com/live2/YOUTUBE_STREAM_KEY;
# Kendi HLS sunucuna devam et
hls on;
hls_path /var/www/hls;
}
Bu özellik hem kendi altyapında hem de büyük platformlarda aynı anda yayın yapmanı sağlıyor.
Sonuç
Nginx RTMP modülü, ticari medya sunucularına kıyasla son derece hafif ve yapılandırılabilir bir alternatif. Twitch benzeri bir altyapı için ihtiyaç duyduğun temel bileşenlerin hepsini (ingest, transcode, HLS/DASH çıktısı, kayıt, auth) tek bir konfigürasyon dosyasından yönetebiliyorsun.
Production’a almadan önce şu noktalara dikkat et: FFmpeg transcoding CPU yoğun bir işlem, yüksek yayıncı sayısı bekliyorsan ya güçlü bir sunucu hazırla ya da GPU tabanlı transcode için NVENC’e geç. Disk alanını düzenli temizlemek için cron job kur. /var/www/hls dizininde biriken .ts dosyaları hızla büyüyebilir. Son olarak, yayın kesintilerini tespit etmek için basit bir uptime monitoring ekle; statsd ya da Prometheus + Grafana ile 5 dakikada güzel bir dashboard hazırlayabilirsin.
Kendi streaming altyapısını kontrol etmenin verdiği özgürlük, biraz kurulum zahmetine kesinlikle değiyor.