自宅でメディアサーバーを運用するのは最高だ——ただし、50GBものBlu-rayリマックスでストレージが埋まり、自動変換する手段がないと気づくまでは。これが約1年前の私の状況だった。Jellyfinで数百本の映画やドラマを管理していたが、8TBのNASはすでに80%が埋まっていた。そこで登場したのがTdarrだ。
Tdarrはメディアライブラリをスキャンし、設定可能な処理プラグイン(H.265、AV1、音声ノーマライズ、字幕抽出)を適用して、複数のワーカーノードでパイプライン全体を管理する分散トランスコードシステムだ。約10か月間本番環境で運用してきたが、結果は安定しており、手作業ゼロで2TB以上のスペースを回収できた。
クイックスタート:5分でTdarrを起動する
DockerとDocker Composeが必要だ。以下は最小構成で、Tdarrサーバーとローカルワーカーを即座に起動できる。
まず、ディレクトリ構造を作成する:
mkdir -p ~/tdarr/{server,configs,logs,transcode-cache}
docker-compose.ymlを作成する:
version: "3.8"
services:
tdarr:
image: ghcr.io/haveagitgat/tdarr:latest
container_name: tdarr
restart: unless-stopped
ports:
- 8265:8265 # Web UI
- 8266:8266 # サーバーポート(ワーカーが接続する)
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Tokyo
- UMASK_SET=002
- serverIP=0.0.0.0
- serverPort=8266
- webUIPort=8265
- internalNode=true # 同じコンテナ内でワーカーを実行
- internalNodeID=main-node
- internalNodeName=LocalNode
volumes:
- ~/tdarr/server:/app/server
- ~/tdarr/configs:/app/configs
- ~/tdarr/logs:/app/logs
- ~/tdarr/transcode-cache:/temp
- /path/to/your/media:/media:rw
docker compose up -d
# Web UIはhttp://your-server-ip:8265でアクセス可能
UIを開くと、内蔵ワーカー(LocalNode)が30秒以内にオンライン表示されるはずだ。これだけでTdarrが動作している。
詳細解説:Tdarrの仕組み
アーキテクチャ:サーバーとノード
Tdarrは役割を明確に分離している:
- サーバー:ライブラリをスキャンし、ファイルと処理状態のデータベースを管理し、トランスコードジョブをキューに入れる。
- ノード(ワーカー):サーバーキューからジョブを取得し、FFmpegまたはHandBrakeを実行し、結果を報告する。
サーバーとノードはサーバーポート(デフォルト8266)を通じて通信する。ノードは完全に別のマシンで実行可能だ——NAS、古いPC、軽いCPUタスクならRaspberry Piでも動作する。
ライブラリとフロー
ログイン後、Librariesに移動してメディアパスを追加する。Tdarrは再帰的にスキャンし、各コンテナから完全なコーデックメタデータを含むファイルリストを作成する。
本当の力はFlowsにある——ノードベースのパイプラインエディタで、各ノードが一つの処理を担当する:コーデックの確認、解像度の確認、FFmpegの実行、ファイルの移動、通知の送信など。コミュニティライブラリには数百の事前構築済みフローが用意されている。
典型的なH.265変換フローは次のようになる:
- コーデックがHEVCでないか確認 → すでにH.265の場合はスキップ
- ファイルサイズが500MBより大きいか確認 → 変換する価値のない小さなファイルはスキップ
-c:v libx265 -crf 22 -preset medium -c:a copyでFFmpegを実行- 出力が入力より小さいか確認 → そうでなければ元に戻し、変換不要としてマーク
- 元ファイルをトランスコード済みバージョンで置き換え
すべてのストリームを保持するH.265用のFFmpeg引数:
-c:v libx265 -crf 23 -preset slow -c:a copy -c:s copy -map 0
フローをライブラリに割り当てた後、ノードを処理開始に設定する。ファイルは次の状態を経由して進む:Not processed(未処理) → Queued(待機中) → Processing(処理中) → Healthy(完了)。
応用編:分散ノードとGPUトランスコード
リモートワーカーノードの追加
ここがTdarrのHomeLabでの真価を発揮する場面だ。私はメインサーバーで1つのワーカーを実行し、日中ほとんど使っていない古いゲーミングPCでもう1つ実行している。
2台目のマシンにはノードイメージのみをデプロイする:
version: "3.8"
services:
tdarr-node:
image: ghcr.io/haveagitgat/tdarr_node:latest
container_name: tdarr-node
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Tokyo
- nodeName=GamePC-Node
- serverIP=192.168.1.100 # TdarrサーバーのIPアドレス
- serverPort=8266
- transcodercputhreads=8
volumes:
- ~/tdarr-node/configs:/app/configs
- ~/tdarr-node/logs:/app/logs
- ~/tdarr-node/transcode-cache:/temp
- /media/library:/media:rw # サーバーが使用するパスと一致させる必要がある
重要な要件:すべてのノードから同じマウントポイントでメディアパスにアクセスできる必要がある。私はすべてのマシンで/media/libraryにNASのメディア共有をNFSでマウントしている。これにより、クラスター全体でTdarrのファイルパスが一致する。
# 各ワーカーマシンでNFS共有をマウント
sudo mount -t nfs 192.168.1.50:/mnt/tank/media /media/library
# 再起動後も永続的にマウントするため/etc/fstabに追加
192.168.1.50:/mnt/tank/media /media/library nfs defaults,_netdev 0 0
NVIDIAによるGPUトランスコード
サーバーにNVIDIA GPUがあれば、NVENCで処理を大幅に高速化できる。まずNVIDIA Container Toolkitをインストールする:
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo systemctl restart docker
次に、TdarrのComposeサービスにGPUアクセスを追加する:
services:
tdarr:
image: ghcr.io/haveagitgat/tdarr:latest
# ... 既存の設定 ...
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
フローでNVENC引数に切り替える:
# NVENC H.265 — CPUのslowプリセットより大幅に高速、ファイルサイズはやや大きい
-c:v hevc_nvenc -preset p4 -cq 24 -c:a copy -c:s copy -map 0
GPUトランスコードは1080pコンテンツでCPUより5〜10倍高速だ。ドラマのエピソード(大量の小さなファイル)にはGPUを使い、映画には時間をかけても圧縮品質が優れるCPUのslowプリセットを使っている。
本番運用から得た実践的なヒント
大量処理の前にフローをテストする
まず3〜5ファイルでテストする。ライブラリをマニュアルモードに設定し、テストファイルをいくつか選んでトランスコードログを注意深く監視する。フローをライブラリ全体に適用する前に、出力品質とファイルサイズを確認する。
失敗したトランスコードから保護する
FFmpegトランスコードステップの直後にサイズ確認ノードを追加する:
- 出力が入力サイズの95%を超える場合 → 元に戻し、変換不要としてマーク
- FFmpegがゼロ以外のコードで終了 → Tdarrが自動的にファイルを元に戻す
Tdarrはトランスコードの成功を確認するまで元ファイルを保持するため、データ損失リスクは低い——ただし、サイズ確認は実際にトランスコード後にファイルが大きくなったケースを検出する(すでに圧縮されたソースでは予想以上に起こりやすい)。
オフ時間帯にトランスコードをスケジュールする
ノードはAPIを通じて一時停止・再開できる。日中のCPU消費を避けるため、cronでスケジュールしている:
# 午前8時にノードを一時停止(業務時間開始)
0 8 * * * curl -s -X POST "http://192.168.1.100:8265/api/v2/update-node" \
-H "Content-Type: application/json" \
-d '{"nodeID": "main-node", "paused": true}' > /dev/null
# 午後10時にノードを再開
0 22 * * * curl -s -X POST "http://192.168.1.100:8265/api/v2/update-node" \
-H "Content-Type: application/json" \
-d '{"nodeID": "main-node", "paused": false}' > /dev/null
トランスコードキャッシュのディスク容量を監視する
/tempボリュームはすぐにいっぱいになる可能性がある。Tdarrは元ファイルを置き換える前に完全な出力ファイルをそこに書き込むため、20GBの4Kファイルの場合、キャッシュに20GB以上の空き容量が必要だ。可能であれば専用SSDパーティションを割り当てる:
# キャッシュの使用量を確認
df -h ~/tdarr/transcode-cache
# Tdarrは完了時に自動クリーンアップするが、クラッシュ後は手動で削除
find ~/tdarr/transcode-cache -name "*.tmp" -mtime +1 -delete
実際に効果的なCRF設定
数か月の調整を経て、以下の設定に落ち着いた:
- アニメ / アニメーション:CRF 20 — フラットな色域はH.265で非常に効率よく圧縮できる
- 実写1080p:CRF 23 — 通常40〜60%のサイズ削減、画質の違いはほぼ判別不可能
- 4K HDR:CRF 20、
-x265-params hdr-opt=1:repeat-headers=1でHDRメタデータを保持 - 古いDVDリップ(480p):スキップ — すでに十分小さく、処理時間をかける価値がない
分散環境でTdarrを運用することで、ストレージ管理が根本的に変わった。初期設定は30分程度だが、一度動き始めれば存在を忘れてしまう——眠っている間にバックグラウンドで静かにファイルを変換してくれる。80%だった8TBのNASが現在55%になり、ライブラリは増え続けている。こういった設置して放置できる自動化こそ、HomeLabを構築する価値そのものだ。

