Nginx ile RTMP Modülü Kurulumu ve Canlı Yayın Sunucusu Oluşturma

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.

Yorum yapın