Jellyfin 是一个开源媒体服务器,可以用来管理电影、电视剧、音乐和照片,并通过浏览器、电视盒子、手机 App 访问。
本文记录在 QNAP NAS 上用 Docker 部署 Jellyfin 的方式。部署方式优先使用 Docker Compose,Container Station 用来查看容器状态和日志。
官方文档入口:
版本说明
本文固定使用 Jellyfin:
jellyfin/jellyfin:10.11.11
不要直接使用 jellyfin/jellyfin:latest。Jellyfin 官方说明 latest 会跟随最新稳定版,包括大版本和小版本变化。家庭媒体库长期运行时,建议固定到具体版本,升级前先备份配置。
官方容器镜像常见标签含义:
latest 最新稳定版,浮动
10 最新 10.Y.Z,浮动
10.11 最新 10.11.Z,浮动
10.11.11 固定具体版本
部署规划
本文假设 QNAP NAS 的 IP 是:
192.168.3.200
Jellyfin 访问地址:
http://192.168.3.200:8096
目录规划:
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose 放 compose.yaml
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/config 放 Jellyfin 配置
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache 放 Jellyfin 缓存和转码临时文件
/share/CACHEDEV2_DATA/Media 放媒体文件
如果你的 QNAP 默认存储池不是 CACHEDEV2_DATA,需要按实际路径修改。可以通过下面命令查看默认数据卷:
getcfg SHARE_DEF defVolMP -f /etc/config/def_share.info
前置条件
QNAP 需要先安装:
Container Station
Docker Engine
Docker Compose
在 QNAP Web 管理页面打开:
App Center -> 搜索 Container Station -> 安装
然后开启 SSH:
控制台与管理工具 -> Telnet / SSH -> 允许 SSH 连接
从电脑登录 NAS:
ssh admin@192.168.3.200
检查 Docker:
docker version
docker compose version
如果 SSH 中找不到 docker,先查找 Container Station 自带的 Docker 路径:
find /share -name docker -type f 2>/dev/null | grep -Ei 'container.*station|/\.qpkg/'
常见路径类似:
/share/CACHEDEV2_DATA/.qpkg/container-station/bin/docker
临时加入 PATH:
export PATH=/share/CACHEDEV2_DATA/.qpkg/container-station/bin:$PATH
如果路径不是 CACHEDEV2_DATA,按实际查到的路径修改。
创建目录
创建 Jellyfin 部署目录:
export NAS_DATA_ROOT=/share/CACHEDEV2_DATA
mkdir -p ${NAS_DATA_ROOT}/DockerDatas/jellyfin/compose
mkdir -p ${NAS_DATA_ROOT}/DockerDatas/jellyfin/config
mkdir -p ${NAS_DATA_ROOT}/DockerDatas/jellyfin/cache
mkdir -p ${NAS_DATA_ROOT}/Media
把电影、电视剧、音乐等文件放到 ${NAS_DATA_ROOT}/Media 下,例如:
/share/CACHEDEV2_DATA/Media/Movies
/share/CACHEDEV2_DATA/Media/TV
/share/CACHEDEV2_DATA/Media/Music
如果你的媒体文件已经在其他共享目录,例如 /share/CACHEDEV2_DATA/Multimedia,后面的 Compose 文件里把媒体路径改成实际目录即可。
Docker Compose 部署
进入部署目录:
cd ${NAS_DATA_ROOT}/DockerDatas/jellyfin/compose
创建 compose.yaml:
cat > compose.yaml <<'EOF'
services:
jellyfin:
image: jellyfin/jellyfin:10.11.11
container_name: jellyfin
restart: unless-stopped
ports:
- "8096:8096/tcp"
- "7359:7359/udp"
environment:
TZ: Asia/Shanghai
JELLYFIN_PublishedServerUrl: http://192.168.3.200:8096
volumes:
- /share/CACHEDEV2_DATA/DockerDatas/jellyfin/config:/config
- /share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache:/cache
- type: bind
source: /share/CACHEDEV2_DATA/Media
target: /media
read_only: false
EOF
这里把媒体目录挂载成只读,Jellyfin 可以扫描和播放,但不能修改媒体文件。这样更适合 NAS 上已经整理好的媒体库。
如果要让 Jellyfin 下载字幕、写入 NFO 或直接管理媒体文件,可以把 read_only: true 改成:
read_only: false
启动:
docker compose up -d
查看状态:
docker compose ps
查看日志:
docker compose logs -f
docker run 部署
如果只是临时测试,也可以直接使用 docker run:
docker run -d \
--name jellyfin \
--restart unless-stopped \
-p 8096:8096/tcp \
-p 7359:7359/udp \
-e TZ=Asia/Shanghai \
-e JELLYFIN_PublishedServerUrl=http://192.168.3.200:8096 \
-v /share/CACHEDEV2_DATA/DockerDatas/jellyfin/config:/config \
-v /share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache:/cache \
--mount type=bind,source=/share/CACHEDEV2_DATA/Media,target=/media,readonly \
jellyfin/jellyfin:10.11.11
长期运行更推荐 Compose,后续升级、备份和迁移都更清楚。
访问和初始化
浏览器访问:
http://192.168.3.200:8096
第一次打开会进入 Jellyfin 初始化向导:
1. 选择语言
2. 创建管理员用户
3. 添加媒体库
4. 配置远程访问
5. 完成初始化
添加媒体库时,容器内路径使用:
/media/Movies
/media/TV
/media/Music
如果页面打不开,先检查:
docker compose ps
docker compose logs -f
curl -I http://127.0.0.1:8096
curl -I http://192.168.3.200:8096
Container Station 中查看
通过 SSH 使用 Docker Compose 启动后,Jellyfin 容器通常也会出现在 Container Station 的容器列表里。
可以在 Container Station 中查看:
容器状态
CPU / 内存占用
端口映射
容器日志
但建议不要在 Container Station 里随手修改容器配置。长期维护以 compose.yaml 为准,避免 GUI 配置和文件配置不一致。
硬件转码
如果 QNAP 是 Intel 或 AMD x86_64 机型,可能可以使用 /dev/dri 做硬件转码。先检查设备是否存在:
ls -l /dev/dri
如果能看到类似:
card0
renderD128
再查看 renderD128 的组 ID:
stat -c '%n %a %U %G %g' /dev/dri/renderD128
示例输出:
/dev/dri/renderD128 660 root render 107
最后一列 107 就是渲染设备的 GID。为了让容器内的 Jellyfin 进程能访问这个设备,可以在 Compose 目录里创建 .env:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
echo "RENDER_GID=$(stat -c '%g' /dev/dri/renderD128)" > .env
cat .env
然后在 compose.yaml 中给 Jellyfin 增加 devices 和 group_add:
services:
jellyfin:
image: jellyfin/jellyfin:10.11.11
container_name: jellyfin
restart: unless-stopped
devices:
- /dev/dri:/dev/dri
group_add:
- "${RENDER_GID}"
ports:
- "8096:8096/tcp"
- "7359:7359/udp"
environment:
TZ: Asia/Shanghai
JELLYFIN_PublishedServerUrl: http://192.168.3.200:8096
volumes:
- /share/CACHEDEV2_DATA/DockerDatas/jellyfin/config:/config
- /share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache:/cache
- type: bind
source: /share/CACHEDEV2_DATA/Media
target: /media
read_only: true
networks:
- homestore
networks:
homestore:
driver: bridge
name: homestore
修改后重启:
docker compose down
docker compose up -d
确认容器里能看到设备:
docker exec -it jellyfin ls -l /dev/dri
然后在 Jellyfin Web 页面中打开:
控制台 -> 播放 -> 转码 -> 硬件加速
Intel 核显一般选择:
Intel Quick Sync
例如 QNAP 使用 Intel Celeron N5095 这类 Intel 核显机型时,优先选择:
Intel Quicksync (QSV)
如果 Quick Sync 不正常,可以退一步测试:
VAAPI
常用设置建议:
硬件加速: Intel Quick Sync
硬件解码: 先勾 H.264、HEVC、MPEG2、VC1、VP9
硬件编码: 开启
允许硬件色调映射: 先关闭,确认普通转码正常后再测试
转码临时路径: 保持默认或使用 /cache
老款 Intel 核显不一定支持 AV1、HEVC 10-bit、HDR 色调映射等能力。不要一次把所有选项都勾上,先让 1080p H.264 / HEVC 转码跑通,再逐项增加。
测试方式:
1. 手机播放一个高码率视频
2. 把质量手动调低,例如 1080p - 8 Mbps
3. 打开播放信息
4. 确认播放方式从 Direct 变成 Transcode
5. 观察 NAS CPU 是否明显低于纯软件转码
同时查看 Jellyfin 日志:
docker compose logs -f
如果硬件转码正常,日志里的 ffmpeg 命令通常会出现和 QSV 或 VAAPI 相关的参数。
注意,修改 compose.yaml 只代表容器能看到 /dev/dri,不代表 Jellyfin 已经启用硬件转码。可以检查配置文件:
grep -n 'HardwareAccelerationType' \
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/config/config/encoding.xml
如果输出是:
<HardwareAccelerationType>none</HardwareAccelerationType>
说明 Jellyfin 后台仍然没有开启硬件加速。需要在 Web 页面里选择 Intel Quick Sync 或 VAAPI 并保存。
也可以通过日志判断当前是不是硬件转码:
docker compose logs -f
如果 ffmpeg 命令里看到:
-codec:v:0 libx264
说明当前还是 CPU 软件转码。如果硬件转码生效,通常会看到:
qsv
vaapi
例如看到下面这些参数,就说明 QSV 已经生效:
-init_hw_device qsv
-codec:v:0 h264_qsv
scale_vaapi
format=qsv
如果 QSV 已经生效但 iPhone 仍然卡,问题就不再是“硬件转码没打开”,而要继续看客户端和播放链路:
播放信息是否仍然是 Direct
是否通过 Safari Web 页面播放
是否走了 HTTPS 反向代理
是否开启了复杂字幕
是否使用了过低码率或频繁拖动进度条
建议优先测试这几种组合:
1. iPhone 直连 http://192.168.3.200:8096
2. 固定质量 1080p 8 Mbps 或 720p 4 Mbps
3. 关闭字幕
4. 使用 Jellyfin App 或外部播放器 VLC
5. 确认播放信息显示 Transcode,而不是 Direct
是否能用硬件转码取决于 NAS CPU、QNAP 系统、驱动、设备权限和视频编码格式。不要一开始就依赖硬解,先确认普通播放正常,再开启硬解测试。
如果开启硬件转码后无法播放,先回到 Jellyfin 后台关闭硬件加速,再查看日志:
docker compose logs -f
手机播放卡顿排查
如果电脑播放正常,但手机播放视频卡顿,先打开手机播放器里的播放信息。看到类似:
质量: 自动 - Direct
播放速度: 1x
这里的 Direct 很关键。它表示 Jellyfin 正在让手机直接播放原始视频文件,NAS 基本没有参与转码。此时卡顿通常不是 Jellyfin 容器本身的问题,而是下面几类原因:
手机 Wi-Fi 信号弱,尤其是 2.4G 网络
原片码率太高,例如 4K、蓝光 Remux、大体积 HEVC
手机硬件或当前播放器对视频编码支持不好
手机实际走了公网、反向代理或弱网络链路
字幕、音轨、封装格式导致手机端播放压力变大
硬件转码只对 Transcode 生效。只要播放信息仍然显示 Direct,即使已经配置好 /dev/dri,NAS 的硬件转码也不会参与这次播放。
先确认手机和电脑是不是同一条访问路径。为了排除反向代理和公网链路,手机先连同一个局域网 Wi-Fi,并直接访问:
http://192.168.3.200:8096
不要一开始就用:
https://jellyfin.jihw.top
如果局域网直连不卡,而域名访问卡,问题多半在 Nginx Proxy Manager、路由器、公网回流、DNS 或外网带宽上。
再看原片码率。播放时打开“播放信息”,重点看:
视频编码: H.264 / HEVC / AV1
分辨率: 1080p / 4K
码率: 多少 Mbps
播放方式: Direct / Direct Stream / Transcode
如果是 Direct,并且原片是高码率 4K 或 HEVC,手机卡顿很常见。可以在手机播放界面把质量从“自动”改成固定码率,例如:
1080p - 10 Mbps
720p - 4 Mbps
这样会强制 Jellyfin 转码,降低手机端和网络压力。转码后再观察:
1. 手机是否不卡了
2. NAS CPU 是否飙高
3. Jellyfin 日志里是否出现 ffmpeg 转码错误
查看日志:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose logs -f
如果强制降低质量后不卡,说明主要问题是原片码率、手机解码能力或 Wi-Fi 带宽。后续可以考虑开启硬件转码。
这种情况可以直接按下面思路处理:
局域网手机播放 1080p: 先试 8~12 Mbps
公网手机播放 1080p: 先试 4~8 Mbps
移动网络播放: 先试 2~4 Mbps
4K 原盘或 Remux: 不建议手机 Direct,优先转码或准备 1080p 版本
如果只是偶尔手机看,可以在客户端播放时手动降低质量。如果经常在手机上看,建议开启硬件转码,或者为高码率影片额外准备一份 1080p / H.264 / 8Mbps 左右的版本。
实际测试时可以按手机稳定性重新定档。如果 1.5 Mbps 稳定,而 3 Mbps 还需要观察,就先把手机端固定在:
720p 1.5 Mbps
然后再逐步测试:
720p 3 Mbps
1080p 4 Mbps
1080p 8 Mbps
哪一档连续播放 10~15 分钟不卡,就先用哪一档。不要只看能否起播,手机端真正的问题往往出现在几分钟后的 HLS 分片获取和缓冲。
如果降低质量后更卡,说明 NAS 正在软件转码但性能不够。此时要么开启 /dev/dri 硬件转码,要么准备适合手机播放的低码率版本。
还有一个实用办法是更换手机端播放器。Jellyfin 手机 App 里可以尝试:
使用集成播放器
使用外部播放器,例如 VLC
关闭或更换复杂字幕
ASS/SSA 特效字幕、PGS 图形字幕在某些客户端上会触发额外处理,低性能手机上容易卡。测试时可以先关闭字幕,确认是不是字幕导致。
iPhone 自动模式播放一段时间后卡住
如果 iPhone 在“自动”质量下播放到 1 分钟左右卡住,但手动降低码率后正常,通常可以这样判断:
自动模式: iPhone 直接播放原片,显示 Direct
降低码率: Jellyfin 转成 HLS 分段流,显示 Transcode
这说明问题主要出在 iPhone 直播放这条链路上,可能是原片封装、60fps、音视频轨道、关键帧、Safari/Web 播放器兼容性或网络缓冲策略导致的。降低码率后变成 HLS 转码流,客户端压力和兼容性问题都会小很多。
可以在 NAS 上看 Jellyfin 日志确认是否转码:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose logs -f
如果日志里的 ffmpeg 命令包含:
-codec:v:0 libx264
说明当前是 CPU 软件转码。开启硬件转码后,日志里通常会出现 qsv 或 vaapi 相关参数。
处理建议:
1. iPhone 客户端不要长期使用自动质量,先固定 1080p 8~12 Mbps
2. 使用 Jellyfin App 时尝试切换集成播放器或外部播放器
3. 关闭复杂字幕测试
4. 开启 QNAP 的 /dev/dri 硬件转码
5. 对特别不兼容的视频,额外准备一份 H.264 / AAC / 1080p 版本
电脑和平板不卡,手机卡
如果同一个视频在电脑和平板上不卡,但华为手机和 iPhone 都卡,基本可以先排除 NAS 磁盘、Jellyfin 容器和整体网络吞吐问题。排查重点放到手机端:
手机是否走浏览器播放,而不是 Jellyfin App
手机是否连到 2.4G Wi-Fi 或弱信号区域
手机是否启用了省电模式、低数据模式、私有地址、代理或 VPN
手机播放信息是否在 Direct / Transcode 之间变化
是否通过 HTTPS 反向代理访问,而电脑和平板用的是内网直连
建议固定一个测试矩阵,不要同时改多个变量:
电脑: http://192.168.3.200:8096 自动质量
平板: http://192.168.3.200:8096 自动质量
手机: http://192.168.3.200:8096 1080p 8 Mbps
手机: http://192.168.3.200:8096 720p 4 Mbps
手机: https://jellyfin.jihw.top 1080p 8 Mbps
如果手机直连内网不卡、域名访问卡,问题在反向代理、DNS、路由器回流或 HTTPS 链路。
如果手机直连内网也卡,但电脑和平板不卡,优先处理手机客户端:
1. 不用 Safari / 手机浏览器,改用 Jellyfin App
2. Jellyfin App 中尝试切换集成播放器或外部播放器
3. 外部播放器优先测试 VLC
4. 关闭字幕
5. 固定质量,不使用自动
QSV 生效后,日志中会出现:
-init_hw_device qsv
-codec:v:0 h264_qsv
如果日志已经是 h264_qsv,但手机仍然卡,就不要继续纠结“硬件转码有没有打开”。下一步应该固定手机质量、换播放器、绕过反向代理测试。
还有一种容易误判的情况:Jellyfin 后台已经开启 QSV,但手机客户端在“自动”质量下仍然选择 Direct。这时日志里只会看到 MediaInfoHelper,不会出现新的 ffmpeg 命令。也就是说硬件转码虽然已经配置好了,但这次播放根本没有用上。
判断方法很简单:播放时打开手机端“播放信息”:
Direct 没有用转码,QSV 不参与
Transcode 正在转码,才会用到 QSV/VAAPI
如果手机端仍然显示 Direct,就把质量固定到低于原片的值,例如:
1080p 8 Mbps
720p 4 Mbps
如果固定质量后日志仍然没有 ffmpeg 命令,说明客户端没有真正触发转码,继续降低质量或换播放器测试。
如果固定质量后日志出现 h264_qsv,但仍然在 1~2 分钟后卡住,优先怀疑这个视频文件本身的封装、时间戳、关键帧或手机端播放器兼容性。可以额外准备一份手机友好的版本:
H.264
AAC
1080p 或 720p
30fps
MP4
faststart
如果日志里反复出现:
Current HLS implementation doesn't support non-keyframe breaks but one is requested
Stopping ffmpeg process with q command
说明手机端在请求 HLS 分片或跳转位置时,服务端需要不断停掉当前转码任务并从新的时间点重新生成分片。这类问题通常不是 NAS 性能不足,而是手机播放器、HLS 分片、源文件关键帧间隔或封装兼容性叠在一起导致的。
实测如果 1.5 Mbps 稳定,而 3 Mbps 仍然在 2~3 分钟附近卡住,就先把手机端固定在稳定档位:
720p 1.5 Mbps
然后再考虑长期方案:
1. 手机端使用外部播放器 VLC / Infuse
2. 避免使用自动质量
3. 关闭字幕测试
4. 给问题视频转一份手机友好版本
5. 用 30fps、固定关键帧间隔、H.264、AAC、MP4 faststart
DLNA 和局域网发现
本文默认使用桥接网络,并映射了:
8096/tcp Web 页面和客户端访问
7359/udp 局域网发现
Jellyfin 官方说明 Docker 默认是 bridge 网络,如果要使用 DLNA,通常需要 host 网络。QNAP 上使用 host 网络可能和 NAS 自身服务端口冲突,建议先不用 DLNA,优先通过浏览器、手机 App、电视客户端手动填写服务器地址:
http://192.168.3.200:8096
Nginx Proxy Manager 反向代理
如果要通过域名访问,例如:
https://jellyfin.jihw.top
可以用 Nginx Proxy Manager 反代到 Jellyfin:
Domain Names: jellyfin.jihw.top
Scheme: http
Forward Hostname/IP: 192.168.3.200
Forward Port: 8096
SSL: Let's Encrypt
Force SSL: 开启
Websockets Support: 开启
同时把 compose.yaml 里的 JELLYFIN_PublishedServerUrl 改成最终访问地址:
environment:
TZ: Asia/Shanghai
JELLYFIN_PublishedServerUrl: https://jellyfin.jihw.top
修改后重启:
docker compose down
docker compose up -d
不要把没有 HTTPS 的 Jellyfin 直接暴露到公网。公网访问建议走 HTTPS、强密码、反向代理、VPN 或内网穿透访问控制。
常用维护命令
进入部署目录:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
停止:
docker compose stop
启动:
docker compose start
重启:
docker compose restart
查看状态:
docker compose ps
查看日志:
docker compose logs -f
备份和恢复
Jellyfin 最重要的是配置目录:
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/config
缓存目录可以不备份:
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache
停机备份:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose stop
tar czf /share/CACHEDEV2_DATA/DockerDatas/jellyfin-backup-$(date +%F).tgz \
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/config \
/share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose/compose.yaml
docker compose start
媒体文件目录一般体积很大,建议通过 QNAP 自己的快照、HBS、外置硬盘或异地备份单独处理。
恢复时保持目录路径一致,然后启动:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose up -d
升级
升级前先备份 config 目录。然后修改 compose.yaml 中的镜像版本,例如从:
image: jellyfin/jellyfin:10.11.11
改成目标版本。
拉取并重建:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose pull
docker compose up -d
查看日志确认启动正常:
docker compose logs -f
不要跨多个大版本直接升级。升级前先看 Jellyfin Releases,确认目标版本是否有数据库迁移、插件兼容性或安全修复说明。
卸载
只删除容器,保留配置和媒体文件:
cd /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
docker compose down
确认不再需要 Jellyfin 后,再删除配置和缓存:
rm -rf /share/CACHEDEV2_DATA/DockerDatas/jellyfin/config
rm -rf /share/CACHEDEV2_DATA/DockerDatas/jellyfin/cache
rm -rf /share/CACHEDEV2_DATA/DockerDatas/jellyfin/compose
不要误删媒体目录:
/share/CACHEDEV2_DATA/Media
小结
QNAP NAS 上部署 Jellyfin 最稳的方式是:Container Station 提供 Docker 环境,实际部署用 Docker Compose 管理。
普通使用只需要 8096/tcp,局域网发现可以加 7359/udp。硬件转码需要确认 /dev/dri 是否存在,并且要单独测试。公网访问不要直接暴露 HTTP,建议通过 Nginx Proxy Manager 配 HTTPS 反向代理。