用 Docker Compose 在 NAS 上部署 Jellyfin,附硬件转码配置
用 Docker Compose 在 NAS 上部署 Jellyfin,附硬件转码配置
乔阳Jellyfin 是一个开源的媒体服务器,把 NAS 里的电影、剧集、音乐整理成可以在手机、电视、浏览器上直接播放的流媒体库。本文记录我在飞牛 OS 上用 Docker Compose 部署它的过程,顺带聊聊硬件转码和权限这块的取舍。
为什么用 Docker 部署
直接装在系统里也不是不行,但媒体服务跑久了会涉及依赖升级、用户隔离、日志位置之类的问题。用容器隔离更干净,更新就是重新拉镜像,迁移到别的机器只要带走 compose 文件和配置目录。飞牛 OS 自带应用商店里的 Jellyfin 版本偏旧,这也是我选 Docker 的直接原因。
准备工作
下面几个条件需要先满足:
- 已配置好 Docker 和 Docker Compose 环境
- NAS 已开启 SSH 并能正常连接
- 国内网络环境下,给 Docker 配好国内镜像加速,否则拉镜像会超时
如果还没装 Docker,以 Ubuntu 为例:
1 | # 更新软件包列表 |
注意 docker-compose(连字符)是 Python 实现的旧版 V1,已经不再维护。现在更推荐用 docker compose(空格)的 V2 插件,安装方式是 apt install docker-compose-plugin。两者命令大体兼容,本文示例两种都能用。
目录结构
我在 NAS 上单独建了一个目录放配置和缓存,和媒体数据分开。路径按你自己的实际情况调整,下面只是示例:
1 | # 配置与缓存目录 |
config 存放 Jellyfin 的设置、元数据库、用户信息,需要持久化,丢了就得重新配置。cache 存放转码临时文件,删掉不影响配置。两者分开的好处是清理缓存时不会误伤配置。
编写 docker-compose.yml
1 | version: "3.8" |
几点说明:
8096是 Jellyfin 的默认 HTTP 端口,访问http://NAS的IP:8096进入初始化界面。/config和/cache是容器内的固定路径,不要改,宿主机路径随意。- 媒体目录挂载到容器的
/media/media,之后在 Jellyfin 后台添加媒体库时填这个路径下的子目录。宿主机路径按你的媒体实际存放位置改。 - 如果让 Jellyfin 把元数据和海报存在 config 目录(默认行为),媒体目录可以只读挂载,写成
/vol2/1000/media:/media/media:ro。只读挂载更安全,真要让它往媒体目录写刮削信息再改回来。 TZ=Asia/Shanghai让容器内时间和日志用东八区,不加的话默认 UTC。version: "3.8"这一行在 Compose V2 里已经被忽略,留着不报错,删掉也行。
启动
进入 compose 文件所在目录:
1 | sudo docker-compose up -d |
查看运行状态:
1 | sudo docker-compose ps |
容器起来后,浏览器打开 http://NAS的IP:8096,跟着向导走完初始化,创建管理员账号,添加媒体库就能用了。
更新镜像用:
1 | sudo docker-compose pull |
硬件转码与 GPU 透传
这是部署 Jellyfin 最值得花时间想清楚的一块。
客户端能直接播放源文件格式时,Jellyfin 只做转封装,几乎不吃 CPU,这叫直通(direct play)。但当客户端不支持源编码,比如 H.265 视频在老电视上播放,Jellyfin 就得实时转码。CPU 软解 1080p 还扛得住,4K 就很吃力,风扇狂转。
有 Intel 核显或独立显卡的话,硬件转码效率高一个数量级。Docker 里要用上它,得把显卡设备透传进容器。
Intel 核显(VAAPI)的写法,在 compose 里加:
1 | devices: |
/dev/dri 是显卡设备节点。group_add 把容器进程加进 video 和 render 组,否则没权限访问设备。组名在不同发行版上可能不存在,更稳的写法是直接填 GID 数字,先用 getent group render video 在宿主机查到 GID 再填进去。
NVIDIA 显卡更麻烦,需要先在宿主机装 nvidia-container-toolkit,然后改用:
1 | deploy: |
容器起来后,去 Jellyfin 后台「播放,转码」里启用硬件转码,选对应的 VAAPI 或 NVIDIA NVENC。Intel 核显一般选 VAAPI,设备填 /dev/dri/renderD128。
老实说,硬件转码能不能跑通很看驱动和内核版本。VAAPI 在某些飞牛 OS 内核上会缺 i915 驱动或固件,花半天调试不奇怪。如果只是自己看,片源都是客户端能直通的格式,软解也够用,别一上来就折腾 GPU。
权限与用户
官方 jellyfin/jellyfin 镜像默认以 root 身份运行容器进程。这意味着容器写出的 config、cache 文件在宿主机上是 root 所有,你用普通账号去删 cache 目录会提示权限不足。
想让它以普通用户跑,在 compose 里加 user: "1000:1000"(换成你实际的 UID:GID),并保证 config、cache 目录的所有者就是这个 UID。media 目录至少要给读权限。
媒体文件如果是 NAS 上其他账号管理的,要注意 UID 对得上,否则容器里读不到文件。这是 NAS 上跑容器最常见的坑。
几点局限
- 这里只走了 HTTP,真要外网访问得套一层反向代理上 HTTPS,别直接把 8096 暴露到公网。
- Jellyfin 的刮削器对中文电影名识别率一般,部分片源需要手动修正元数据。
- 转码烧字幕时,容器里缺中文字体会显示方块,需要把字体挂进
/config/fonts。
整体来说,Docker 部署 Jellyfin 本身不复杂,半小时能跑起来。真正费时间的是硬件转码和媒体库整理,这两块值得单独花时间。







