본문 바로가기

미디어서버(Nginx RTMP)

미디어 서버 구축하기 EC2+RTMP+NginX+FFmpeg

대략적인 서비스 처리의 순서

영상 소스(OBS Studio) -> RTMP로 실시간 전송 -> [플랫폼에서 수신]->[실시간 트랜스코딩]->[실시간 .m3u8 및 .ts 생성]-> 클라이언트 스트리밍

 

EC2 포트 열어주기

 

필요한 패키지 설치

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install nginx
sudo apt install libnginx-mod-rtmp # nginx와 rtmp를 위한 패키지
sudo apt install net-tools # ufw status 확인 시 필요

 

방화벽 설정

sudo ufw allow 22/tcp # ssh 프로토콜
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp # https 프로토콜을 쓴다면
sudo ufw allow 1935/tcp
sudo ufw allow 8088/tcp

 

NginX 설정

# sudo vi /etc/nginx/nginx.conf

# RTMP 모듈 설정 시작
rtmp {
    # RTMP 서버 설정 시작
    server {
        # RTMP 포트 번호
        listen 1935;

        # 데이터 전송 시 4KB 블록 크기
        chunk_size 4096;

        # RTMP 어플리케이션 설정 시작
        application live {
            # 라이브 스트리밍 활성화
            live on;

            # 녹화 비활성화
            record off;

            # HLS 설정 시작
            hls on;
            # HLS 저장 경로
            hls_path /var/www/html/stream/hls;
            # HLS 단편(fragment) 길이
            hls_fragment 3s;
            # HLS 플레이리스트 길이
            hls_playlist_length 5s;
            # HLS 정리(삭제) 설정 (옵션으로 주석처리)
            #hls_cleanup off;

            # RTMP 어플리케이션 설정 종료
        }
        # RTMP 서버 설정 종료
    }
    # RTMP 모듈 설정 종료
}

 

위의 값들 중 추후 성능 및 사용자 환경에 따라 조절을 고려해볼만한 값들

  1. chunk_size:
    • 설명: RTMP 프로토콜에서 사용되는 데이터 전송의 기본 블록 크기를 나타냅니다.
    • 조정 고려사항:
      • 큰 파일을 다루거나 네트워크 대역폭이 높을수록 큰 값이 유리할 수 있습니다.
      • 하지만, 작은 파일이나 네트워크 대역폭이 제한된 경우에는 작은 값으로 조정할 수 있습니다.
  2. hls_fragment:
    • 설명: HLS 스트리밍에서 각 단편(fragment)의 길이를 나타냅니다.
    • 조정 고려사항:
      • 사용자 경험 및 네트워크 대역폭에 따라 조절될 수 있습니다.
      • 작은 값은 빠른 스트리밍 시작을 제공하지만, 네트워크 비용이 증가할 수 있습니다.
      • 긴 값은 전체 스트림의 지연을 감소시키지만, 재생 시작이 느려질 수 있습니다.
  3. hls_playlist_length:
    • 설명: HLS 스트리밍에서 플레이리스트의 길이를 나타냅니다.
    • 조정 고려사항:
      • 스트리밍의 부드러움과 지연 시간에 영향을 미칩니다.
      • 작은 값은 더 빠른 플레이리스트 갱신을 의미하지만, 클라이언트 측에서 지연이 발생할 수 있습니다.
      • 큰 값은 플레이리스트 갱신이 느리지만, 부드러운 스트리밍을 제공합니다.

코드에 적혀 있지 않지만 나중에 고려해볼 만한 것들

  1. worker_processes:
    • 설명: Nginx가 사용하는 worker 프로세스의 수를 나타냅니다.
    • 고려사항: 서버의 코어 수 및 가용 리소스에 따라 조절합니다. 보통 코어 수에 맞춰 설정합니다.
  2. worker_connections:
    • 설명: 각 worker 프로세스가 동시에 처리할 수 있는 연결 수를 나타냅니다.
    • 고려사항: 네트워크 연결 수에 따라 조절하며, 고가용성을 위해 높은 값이 필요할 수 있습니다.
  3. events 블록의 multi_accept:
    • 설명: 여러 연결을 동시에 수락할 것인지 여부를 결정합니다.
    • 고려사항: 높은 동시 접속을 처리할 때는 on으로 설정하면 유용할 수 있습니다.
  4. rtmp 블록의 rtmp_auto_push:
    • 설명: 자동으로 푸시 모드를 사용할 것인지 여부를 결정합니다.
    • 고려사항: 특정 요구사항에 따라 설정하며, 필요에 따라 on 또는 off로 조절합니다.
  5. rtmp 블록의 rtmp_max_streams:
    • 설명: 각 RTMP 어플리케이션에서 동시에 처리할 수 있는 최대 스트림 수를 나타냅니다.
    • 고려사항: 서버의 성능 및 사용 패턴에 따라 조절하며, 초과할 경우 연결이 거부될 수 있습니다.
  6. http 블록의 sendfile:
    • 설명: 정적 파일을 전송할 때 sendfile을 사용할지 여부를 결정합니다.
    • 고려사항: 정적 파일 서비스를 위해 on으로 설정하면 성능이 향상될 수 있습니다.
  7. http 블록의 tcp_nodelay 및 tcp_nopush:
    • 설명: TCP_NODELAY 및 TCP_NOPUSH 옵션을 사용할지 여부를 결정합니다.
    • 고려사항: 네트워크 튜닝을 위해 필요에 따라 설정하며, 일부 경우에는 성능 향상을 가져올 수 있습니다.
#sudo vi /etc/nginx/sites-avaliable/default

server {
    listen 8088;

    location / {
        add_header Cache-Control no-cache;
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Expose-Headers' 'Content-Length';

        # :8088 의 root 경로를 지정
        root /var/www/html/stream/hls;

        types {
            application/vnd.apple.mpegurl m3u8;
        }
    }
}

 

참고사항

Nginx RTMP 모듈을 사용하여 라이브 스트리밍을 설정하면, 기본적으로 H.264(비디오), AAC(오디오) 코덱이 사용된다.

이 둘은 대부분의 브라우저 및 플랫폼에서 지원되는 표준 코덱이기에 일반적으로 문제가 없지만

꼭 다른 특정 코덱을 사용해야겠다면, Nginx RTMP 모듈의 설정에서 'exec' 블록을 사용해 FFmpeg 명령어를 통해 변경 가능하다

#예시
application live {
    live on;
    exec_push ffmpeg -i rtmp://source_server/source_stream -c:v libx264 -c:a aac -f flv rtmp://localhost/myapp/mylivestream;
}

 

그리고 만약 화질을 설정하고싶다면

이 또한 FFmpeg 명령어를 통해 변경 가능하다.

-b:v 옵션을 사용하여 비디오 비트레이트를 설정하고, -s 옵션을 사용하여 해상도를 설정하면 된다.

#예시
application live {
    live on;
    exec_push ffmpeg -i rtmp://source_server/source_stream -c:v libx264 -b:v 1500k -s 1280x720 -c:a aac -f flv rtmp://localhost/myapp/mylivestream;
}

브라우저에서 확인 해보자

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script src="https://vjs.zencdn.net/8.3.0/video.min.js"></script>
    <title>Hls Practice</title>
    <style>
        video {
            max-width: 500px;
            width: 100%;
            max-height: 500px;
            height: 100%;
            object-fit: fill;
        }
    </style>
</head>

<body>
<!--
    controls : 사용자가 비디오 컨트롤이 가능하게 할 수 있다
    playsinline : 전체 화면 방지이다
    autoplay : 자동재생이며 , 정책상 음소거 상태에서 가능하다.
-->
<video id="video" controls playsinline autoplay></video>


<script>
    /* video Element */
    let video = null;
    /* 샘플 m3u8 url */
    let videoSrc = 'http://ip주소:포트/스트림키.m3u8';

    /* initVideo */
    const initVideo = () => {
        video = document.querySelector('#video')
    }

    /* DOMContentLoaded 로드를 통해 video Element 담기*/
    window.addEventListener("DOMContentLoaded", () => {
        initVideo();
    })


    /* initHls : hls를 초기화 하는 함수 */
    const initHls = () => {
        if (Hls.isSupported()) {
            hls = new Hls({
                autoStartLoad: false,
            });
            hls.loadSource(videoSrc);
            hls.attachMedia(video);
            hls.startLoad();
        }
        /* ios/safari 같은 경우에 hls가 built-in 되어있다.*/
        else {
            video.src = videoSrc;
        }
    }

    /* DOMContentLoaded 로드를 통해 video Element 담기*/
    window.addEventListener("DOMContentLoaded", () => {
        initVideo();
        initHls();
    })

</script>
</body>

</html>

 

 

보안에 대한 문제

현재 상태는 서버의 주소만 알면 누구나 서버에 접근이 가능해 자원을 잡아먹거나 영상 탈취 가능 등 보안에 문제가 있다

이 문제를 해결하기 위해

Nginx RTMP 모듈에서 사용되는 두 가지 이벤트 핸들러(hook) on_publish  on_play를 사용해서 접근에 제한을 둘 예정이다.

on_publish : 클라이언트가 스트림을 퍼블리시(방송 시작)할 때 발생.

on_play : 클라이언트가 스트림을 플레이(시청 시작)할 때 발생

 

서버단에서 키발급 후 그 키의 정보를 저장하고

application live {
    live on;
    on_publish http://localhost:8080/check-publish-auth;
}

이렇게 인증 절차를 해볼 생각