2026年9月8日
2026年9月8日
NginxでHLS配信を設定する方法|ffmpegでの変換とRTMPモジュールでのライブ配信
HLS(HTTP Live Streaming)は、動画を数秒ずつのファイル(セグメント)に分け、その一覧(プレイリスト、拡張子 .m3u8)と一緒に普通の HTTP で配信する方式です。Apple が策定し、RFC 8216 として公開されています。プレイヤーはプレイリストを読み、セグメントを順に取得して再生します。
Nginx から見ると、HLS の配信は .m3u8 と .ts という静的ファイルを返すだけです。オープンソース版の Nginx に HLS への変換機能は無いため、変換は次のどちらかで行います。
| 用途 | 変換するもの | Nginx の役割 |
|---|---|---|
| 録画済みの動画(VOD) | ffmpeg で事前にプレイリストとセグメントを作る | 静的ファイルとして配信する |
| ライブ配信 | nginx-rtmp モジュールが、受け取った RTMP の映像をその場でセグメントにする | RTMP を受け取り、作られたファイルを HTTP で配信する |
公式ドキュメントにある hls ディレクティブ(ngx_http_hls_module、MP4 を要求時に HLS に変換する機能)は、商用版の NGINX Plus でだけ使えます。hls_fragment や hls_playlist_length は nginx-rtmp モジュールのディレクティブで、http ブロックの location には書けません。
この記事の手順は、Debian 13 の Nginx 1.26.3・ffmpeg 7.1.5・libnginx-mod-rtmp 1.2.2 で、変換・配信・ライブの取り込みまで動作を確認しました(2026年11月時点)。
録画済みの動画を HLS で配信する
1. ffmpeg と Nginx を入れる
sudo apt update
sudo apt install nginx ffmpeg
2. MP4 を HLS に変換する
sudo mkdir -p /var/www/hls/vod
sudo ffmpeg -i input.mp4 \
-c:v libx264 -preset veryfast -crf 23 -g 60 -keyint_min 60 -sc_threshold 0 \
-c:a aac -b:a 128k \
-f hls -hls_time 6 -hls_playlist_type vod \
-hls_segment_filename /var/www/hls/vod/seg_%03d.ts \
/var/www/hls/vod/index.m3u8
| オプション | 意味 |
|---|---|
-c:v libx264 / -c:a aac |
多くの端末で再生できる H.264 と AAC に変換する |
-g 60 -keyint_min 60 -sc_threshold 0 |
キーフレームの間隔を 60 フレームに固定する(30fps なら 2 秒ごと) |
-hls_time 6 |
1 セグメントの目安の長さ(秒)。セグメントはキーフレームの位置で切られる |
-hls_playlist_type vod |
全セグメントを載せたプレイリストを作り、末尾に #EXT-X-ENDLIST を付ける |
-hls_segment_filename |
セグメントのファイル名。%03d が連番になる |
元の動画がすでに H.264 と AAC なら、-c:v libx264 ... と -c:a aac ... の代わりに -c copy を指定すると再変換せずに分割できます。ただしセグメントはキーフレームでしか切れないため、キーフレームの間隔が長い動画では、セグメントが -hls_time より長くなります。
20 秒のテスト動画を変換したところ、次のプレイリストと 4 つのセグメントができました。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:6.000000,
seg_000.ts
#EXTINF:6.000000,
seg_001.ts
#EXTINF:6.000000,
seg_002.ts
#EXTINF:2.000000,
seg_003.ts
#EXT-X-ENDLIST
古い記事に見られる -hls_segment_time というオプションは ffmpeg にありません。セグメントの長さは -hls_time で指定します。
3. Nginx で配信する
.m3u8 と .ts の MIME タイプは、Debian 13 の Nginx では /etc/nginx/mime.types に最初から入っています。お使いの環境でも確認します。
grep -n "m3u8\|mp2t" /etc/nginx/mime.types
37: application/vnd.apple.mpegurl m3u8;
88: video/mp2t ts;
表示されない場合は、location に types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } を書きます。
配信の設定です。Debian/Ubuntu なら /etc/nginx/sites-available/ にファイルを作り、sites-enabled にリンクを張ります。
server {
listen 80;
server_name video.example.com;
location /hls/ {
root /var/www;
location ~ \.m3u8$ {
add_header Cache-Control "no-cache";
add_header Access-Control-Allow-Origin "*";
}
location ~ \.ts$ {
add_header Cache-Control "max-age=86400";
add_header Access-Control-Allow-Origin "*";
}
}
}
root /var/www;により、/hls/vod/index.m3u8は/var/www/hls/vod/index.m3u8を返します。- プレイリストは更新されることがあるので
no-cache、セグメントは内容が変わらないので長めにキャッシュさせています。 Access-Control-Allow-Originは、別のドメインのページに置いたプレイヤー(hls.js など)から読み込むために必要です。*ではなく、プレイヤーを置くサイトのオリジン(例:https://www.example.com)に絞ることもできます。
sudo nginx -t
sudo systemctl reload nginx
curl -sI http://video.example.com/hls/vod/index.m3u8
確認環境では Content-Type: application/vnd.apple.mpegurl と、指定したヘッダーが返りました。ffprobe で URL を読むと、20 秒の動画として認識されます。
ffprobe -v error -show_entries format=duration http://video.example.com/hls/vod/index.m3u8
4. ブラウザーで再生する
Safari(macOS・iOS)は <video> 要素に .m3u8 の URL を指定するだけで再生できます。ブラウザーによってはそのままでは再生できないため、hls.js などの JavaScript のプレイヤーを使うと、より多くのブラウザーで再生できます。動作の確認には、VLC メディアプレーヤーの「ネットワークストリームを開く」に URL を入力する方法もあります。
ライブ配信(RTMP で受けて HLS で配る)
OBS Studio などの配信ソフトは RTMP で映像を送ります。nginx-rtmp モジュールを使うと、Nginx が RTMP を受け取り、HLS のセグメントを書き出します。このモジュールはサードパーティー製で、Debian 13 では libnginx-mod-rtmp パッケージで入ります。
sudo apt install libnginx-mod-rtmp
RTMP の設定
rtmp ブロックは http ブロックの中ではなく、nginx.conf の一番外側に書きます。ここでは別ファイルにして、nginx.conf の末尾(http { ... } の外)で読み込みます。
# /etc/nginx/rtmp.conf
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
live on;
record off;
allow publish 127.0.0.1;
deny publish all;
allow play all;
hls on;
hls_path /var/www/hls/live;
hls_fragment 3s;
hls_playlist_length 60s;
}
}
}
# /etc/nginx/nginx.conf の末尾に追加
include /etc/nginx/rtmp.conf;
| ディレクティブ | 意味 |
|---|---|
allow publish / deny publish |
映像を送ってよい IP アドレス。配信ソフトを動かすパソコンのアドレスを許可する |
hls on |
受け取った映像を HLS に変換する |
hls_path |
セグメントとプレイリストを書き出すディレクトリ |
hls_fragment |
セグメントの長さ。実際にはキーフレームの位置で切られる |
hls_playlist_length |
プレイリストに載せる時間の長さ |
書き出し先のディレクトリは、Nginx のワーカーのユーザー(Debian/Ubuntu では www-data)が書き込めるようにします。
sudo mkdir -p /var/www/hls/live
sudo chown www-data:www-data /var/www/hls/live
sudo nginx -t
sudo systemctl reload nginx
ファイアウォールを使っている場合は、配信ソフトを動かす場所から TCP 1935 番ポートに届くようにします。
映像を送って確認する
OBS Studio では、配信の設定でサーバーに rtmp://サーバーのアドレス/live、ストリームキーに stream などの名前を入れます。ffmpeg で試す場合は次のとおりです。
ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast -g 60 -c:a aac -f flv rtmp://127.0.0.1/live/stream
送っている間、hls_path にストリームキーの名前でプレイリストとセグメントができます。
$ ls /var/www/hls/live
stream-0.ts stream-1.ts stream-2.ts stream-3.ts stream.m3u8
視聴する URL は、前の節の location /hls/ の設定で http://video.example.com/hls/live/stream.m3u8 になります。確認環境では、2 秒ごとにキーフレームを入れた映像で hls_fragment 3s を指定したところ、セグメントは約 4 秒になりました。セグメントの長さを指定どおりにするには、配信ソフト側のキーフレーム間隔を合わせます。
注意点
- HLS の URL は、知っていれば誰でも再生できます。公開したくない動画は、Basic 認証や IP アドレスの制限、署名付き URL(
secure_linkモジュール)などで保護します。 - RTMP の受け口(
allow publish)を全体に開くと、第三者が映像を送り込めます。許可する IP アドレスを絞ってください。 - 視聴者が増えると、配信量はおおむね「ビットレート × 同時視聴者数」になります。回線とサーバーの転送量の上限を確かめ、必要なら CDN を前に置きます。
- 本番では HTTPS で配信します。HTTPS のページに置いたプレイヤーから HTTP の動画は読み込めません。
Nginx の CORS の設定は NginxでCORSを設定する方法、HTTPS 化は NginxとCertbotでSSL証明書を設定する方法 で説明しています。