動画ファイルを HLS(HTTP Live Streaming)に変換して Nginx で配信する手順をまとめました。
「YouTube のような動画配信を自分のサーバーでやってみたい」という相談を受けることがあります。実は Ubuntu 24.04 + FFmpeg + Nginx の3本セットがあれば、ブラウザで再生できる VOD 環境を1時間もかからず構築できます。正直、HLS の仕組みを理解してしまえばコマンドは10行に満たないので、思ったより簡単でした。
この記事では Ubuntu 24.04.4 LTS で実際に FFmpeg 6.1.1 を動かし、テスト動画を HLS に変換した実出力をそのまま載せています。
この記事のポイント
apt install ffmpeg nginxだけで HLS 配信に必要なツールが揃う(Ubuntu 24.04 標準リポジトリ)-hls_time 4と-hls_playlist_type vodを指定するだけで.m3u8+.tsセグメントが生成される- 実測では 30秒動画 → 約1.3秒で変換完了(約24倍速)、生成サイズ 984KB
- アダプティブビットレート(360p+720p 同時出力)は
-filter_complex splitと-var_stream_mapで対応できる - Nginx 側は
m3u8とtsの MIME タイプ設定+ CORS ヘッダーが必須
目次
- HLS(HTTP Live Streaming)とは
- FFmpeg と Nginx のインストール
- シングルビットレート HLS への変換
- Nginx で HLS コンテンツを配信する
- ブラウザで再生する(hls.js)
- アダプティブビットレート HLS(360p + 720p)
- よくあるエラーと解決策
- まとめ
HLS(HTTP Live Streaming)とは
HLS は Apple が開発した動画配信プロトコルで、いまでは YouTube・Netflix・Twitch でも使われています。仕組みはシンプルで、動画を数秒ごとの小さなファイル(.ts セグメント)に分割し、どのファイルをどの順で取得するかを .m3u8(プレイリスト)に記述します。
ブラウザはまず .m3u8 を取得 → そこに書かれた .ts を順番に HTTP でダウンロードして再生します。特別な配信サーバーは必要なく、ただの静的ファイルとして Nginx で配信できるのが最大の利点です。
| プロトコル | 配信形式 | 必要なサーバー | ブラウザ対応 |
|---|---|---|---|
| HLS | .m3u8 + .ts |
静的ファイルサーバー(Nginx 可) | Safari ネイティブ、他は hls.js |
| RTMP | ストリーム | RTMP 対応サーバー必須 | Flash が必要(現在非推奨) |
| DASH | .mpd + .m4s |
静的ファイルサーバー可 | dash.js が必要 |
FFmpeg と Nginx のインストール
Ubuntu 24.04 の標準リポジトリには FFmpeg 6.1.1 が収録されています。apt install 1コマンドで H.264・AAC・HLS 出力が揃います。

Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists… Done
$ sudo apt-get install -y ffmpeg nginx
The following additional packages will be installed:
libavcodec60 libavformat60 libavutil58 libswscale7 …
Setting up ffmpeg (7:6.1.1-3ubuntu5) …
Setting up nginx (1.24.0-2ubuntu7.12) …
インストール後にバージョンを確認します。
ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 13 (Ubuntu 13.2.0-23ubuntu3)
$ nginx -v
nginx version: nginx/1.24.0 (Ubuntu)
$ ffmpeg -formats 2>/dev/null | grep hls
DE hls Apple HTTP Live Streaming
Ubuntu 24.04 に入る FFmpeg は libx264(H.264 エンコーダ)・libx265(H.265)・AAC すべてが有効です。追加ビルドは不要です。
シングルビットレート HLS への変換
まず基本形から始めます。MP4 ファイルを index.m3u8 + seg000.ts, seg001.ts, … に変換するコマンドです。
$ ffmpeg -i input.mp4 \
-c:v libx264 -preset fast -crf 23 \
-c:a aac -b:a 128k \
-hls_time 4 \
-hls_playlist_type vod \
-hls_segment_filename ‘hls/seg%03d.ts’ \
hls/index.m3u8
主なオプションの意味です。
| オプション | 意味 |
|---|---|
-c:v libx264 |
映像を H.264 でエンコード |
-preset fast |
エンコード速度優先(品質と速度のバランス) |
-crf 23 |
品質固定モード(0〜51、低いほど高品質。23 が標準) |
-c:a aac -b:a 128k |
音声を AAC 128kbps でエンコード |
-hls_time 4 |
セグメント長の目安(秒)。実際はキーフレームに合わせてカット |
-hls_playlist_type vod |
VOD 用プレイリスト(末尾に #EXT-X-ENDLIST を追記) |
-hls_segment_filename |
セグメントファイル名のパターン |
hls_time の注意点
-hls_time 4 は「4秒ごとに切る」ではなく「最低でも4秒、キーフレームが来たら切る」という意味です。入力動画のキーフレーム間隔が長い場合(デフォルト2秒周期でエンコードされた動画でも GOP 設定次第では変わる)、実際のセグメント長はそれより長くなります。実測では 30秒動画 → 4本(各〜8秒)になりました。
変換すると以下の出力が得られます。実際に Ubuntu 24.04 コンテナで計測した結果です。

30秒の動画(H.264 CRF23)を変換した実測値です。
- 変換速度:約 24倍速(1.3秒で完了)
- セグメント数:4本(各〜8秒)
- 合計サイズ:984KB
Nginx で HLS コンテンツを配信する
変換したファイルを Nginx で公開します。ここで詰まりやすいのが MIME タイプの設定です。.m3u8 と .ts は Nginx のデフォルト設定に含まれていないため、明示的に指定しないと ブラウザが正しく認識できません。
listen 80;
server_name example.com; # ← 自分のドメインに変更
root /var/www/html;
location /hls/ {
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers *;
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
}
}

設定を反映させます。
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx
HLS ディレクトリへコンテンツを配置します。
$ sudo cp hls/*.m3u8 hls/*.ts /var/www/html/hls/
$ curl -I http://localhost/hls/index.m3u8
HTTP/1.1 200 OK
Content-Type: application/vnd.apple.mpegurl
Access-Control-Allow-Origin: *
Content-Type: application/vnd.apple.mpegurl が返れば正しく設定できています。
ブラウザで再生する(hls.js)
Safari はネイティブで HLS を再生できますが、Chrome や Firefox は HLS を直接再生できません。hls.js を使うことで MSE(Media Source Extensions)対応のすべてのブラウザで再生できます。

シンプルなプレーヤー HTML の例です。CDN 経由で hls.js を読み込むだけなので、フレームワーク不要です。
<script src=”https://cdn.jsdelivr.net/npm/hls.js@latest”></script>
<video id=”video” controls></video>
<script>
var video = document.getElementById(‘video’);
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(‘/hls/index.m3u8’);
hls.attachMedia(video);
} else if (video.canPlayType(‘application/vnd.apple.mpegurl’)) {
video.src = ‘/hls/index.m3u8’; // Safari
}
</script>
ブラウザは index.m3u8 を取得し、記載されたセグメントを順に HTTP リクエストで取得して再生します。

アダプティブビットレート HLS(360p + 720p)
回線速度に応じて品質を自動切り替えするアダプティブビットレート(ABR)を設定します。FFmpeg の -filter_complex と -var_stream_map を使って、1コマンドで複数品質のセグメントと master.m3u8 を同時に出力できます。
$ ffmpeg -i input.mp4 \
-filter_complex ‘[v:0]split=2[v360][v720]’ \
-map ‘[v360]’ -map ‘[v720]’ -map 0:a -map 0:a \
-c:v libx264 -preset fast \
-c:a aac \
-b:v:0 500k -s:v:0 640×360 \
-b:v:1 1500k -s:v:1 1280×720 \
-b:a:0 64k -b:a:1 128k \
-hls_time 4 \
-hls_playlist_type vod \
-hls_segment_filename ‘hls_multi/%v/seg%03d.ts’ \
-master_pl_name master.m3u8 \
-var_stream_map ‘v:0,a:0,name:360p v:1,a:1,name:720p’ \
‘hls_multi/%v/index.m3u8’
real 0m1.861s (30秒動画を約1.9秒で変換 ≈ 16倍速)
実測結果です。30秒の動画(1280×720 入力)を 2品質同時変換した場合の数値です。


生成された master.m3u8 は次の形式になります。hls.js はこのファイルを読んで、接続速度に合わせて 360p と 720p を自動で切り替えます。
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=620400,RESOLUTION=640×360,CODECS=”avc1.f4001e,mp4a.40.2″
360p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1790800,RESOLUTION=1280×720,CODECS=”avc1.f4001f,mp4a.40.2″
720p/index.m3u8
アダプティブ配信の場合、プレーヤー側の loadSource には master.m3u8 を渡します。
hls.attachMedia(video);
よくあるエラーと解決策
エラー1:動画がブラウザで再生されない(CORS エラー)
Chrome の開発者ツールのコンソールに has been blocked by CORS policy と表示される場合、Nginx の CORS ヘッダーが抜けています。/hls/ のブロックに add_header Access-Control-Allow-Origin *; を追加して nginx -t && systemctl reload nginx を実行してください。
エラー2:m3u8 を開くと 404 になる
HLS ファイルを /var/www/html/hls/ にコピーしたか確認します。また ls -la /var/www/html/hls/ でパーミッションを見てください。Nginx は www-data ユーザーで動くため、ファイルのオーナーが root のままだと読めないことがあります。chmod 644 で読み取り権限を付与してください。
エラー3:変換中に「Unknown encoder ‘libx264’」
FFmpeg を自前ビルドしたか、Ubuntu の場合は ffmpeg パッケージ(universe リポジトリ)でなく libav* 系の別パッケージが入っている可能性があります。apt-get install ffmpeg で入れ直し、ffmpeg -codecs | grep libx264 で確認してください。Ubuntu 24.04 の標準 ffmpeg は libx264 有効状態でビルドされています。
エラー4:セグメント長が指定より長い
前述のとおり、-hls_time はキーフレームに合わせてカットするため、実際のセグメント長は指定より長くなります。精密に区切りたい場合は -force_key_frames "expr:gte(t,n_forced*2)" を追加して入力に強制的にキーフレームを打ち込む方法があります。ただし再エンコード時間が増えます。
まとめ
Ubuntu 24.04 上で FFmpeg + Nginx を使った HLS/VOD 配信の手順をまとめました。
- Ubuntu 24.04 標準の
ffmpeg 6.1.1は libx264・AAC・HLS フォーマットをすべてサポート済み - 基本コマンドは
-hls_time 4 -hls_playlist_type vod -hls_segment_filenameの3オプション - 実測では 30秒動画 → 約1.3秒(24倍速)で変換、合計 984KB
- Nginx 側は
m3u8の MIME タイプと CORS ヘッダーが必須 - アダプティブビットレートは
-filter_complex split+-var_stream_mapで対応できる - ブラウザ再生には
hls.js(CDN 経由でロード可)を使う
自分の VPS でこの構成を動かすには、外部アクセス可能なサーバーが必要です。コスト感を比較したい場合は VPS 比較記事も参考にしてください。



コメント