Lyrion Music Server 9.1.1 Docker Compose 部署指南

基于 Lyrion Music Server 9.1.1 实测:lmscommunity 镜像选型、Compose 编排、端口映射语义、数据持久化、运维命令与播放器排障实录。

Lyrion Music ServerLyrionDockerDocker Compose流媒体媒体服务器2026/10/29

Lyrion Music Server 9.1.1 Docker Compose 部署指南

目标:在一台 Linux 服务器上用 Docker Compose 完成音乐服务器 Lyrion Music Server 9.1.1 与软件播放器 squeezelite 的整套部署,讲清三个服务端口的映射语义与三组数据卷的持久化边界,并沉淀部署过程中的实测排障记录。本文所有命令与回显均在真实部署环境执行验证。

一、环境信息

项目值说明
宿主系统Ubuntu(x86_64)Docker 环境由宿主提供
Docker 版本29.9.2docker --version 实测
Compose 版本v5.6.1docker compose version 实测
服务端镜像lmscommunity/lyrionmusicserver:9.1.1社区官方维护镜像
播放器镜像giof71/squeezelite:stable-alsa软件播放器,用于验证播放链路
服务端版本9.1.1(构建号 1779815526,2026-06-17 构建)启动日志实测
Perl 运行时perl 5.036000(x86_64-linux-gnu-thread-multi)启动日志实测
网络模式bridge,独立子网 10.89.56.0/24compose 自定义网络

服务端启动日志第一行与初始化完成行,作为版本与运行时的实测依据:

[26-10-28 17:06:40.7660] main::init (282) Starting Lyrion Music Server (v9.1.1, 1779815526, Wed Jun 17 12:31:49 UTC 2026) perl 5.036000 - x86_64-linux-gnu-thread-multi
[26-10-28 17:06:40.9653] main::init (555) Server done init: http://10.89.56.2:9000

第一行给出版本、构建号与构建日期;第二行说明服务端在网络内注册的地址(10.89.56.2 为服务端在 compose 网络内的地址,9000 为服务端内部 Web 端口)。

二、镜像选型说明

2.1 服务端镜像

选型结论:使用 lmscommunity/lyrionmusicserver,版本 tag 固定为 9.1.1,不使用 latest。

实测镜像元数据(docker image inspect 输出节选):

{
  "Size": 348577382,
  "Created": "2026-06-17T15:15:31.068026768Z",
  "Architecture": "amd64",
  "Config": {
    "Env": ["PUID=499", "PGID=100", "HTTP_PORT=9000"],
    "Entrypoint": ["start-container"],
    "ExposedPorts": {
      "3483/tcp": {}, "3483/udp": {}, "9000/tcp": {}, "9090/tcp": {}
    },
    "Volumes": {"/config": {}, "/music": {}, "/playlist": {}},
    "WorkingDir": "/config"
  }
}

四个事实直接影响 compose 写法:

  1. 内置三组环境变量默认值:PUID=499、PGID=100、HTTP_PORT=9000,compose 中按需覆盖。
  2. 声明了四个服务端口:3483(TCP 与 UDP 两种协议都要)、9000、9090。
  3. 声明了三个数据卷:/config、/music、/playlist,持久化方案围绕它们设计。
  4. 入口脚本为 start-container:脚本内以 su squeezeboxserver 降权启动主程序,实测容器内进程树为 root(入口脚本)→ squeezeboxserver(Perl 主程序)。

2.2 播放器镜像

squeezelite 是 Squeezebox 协议的开源软件模拟器,把它跑起来就等价于房间里多了一个 Squeezebox 播放器,是零硬件成本验证 LMS 播放链路的标准做法。选择 giof71/squeezelite:stable-alsa 的理由:该镜像将 squeezelite 的常用参数全部环境变量化,且 stable-alsa tag 与服务端同源稳定。

技术拓展:PUID/PGID 权限模型 lmscommunity 系列镜像用 PUID/PGID 两个环境变量决定容器内业务进程的文件读写身份,入口脚本启动时会按其调整 /config 等挂载目录的属主。本例宿主上有 uid/gid 为 1000 的运维账号,故设 PUID=1000、PGID=1000,使宿主直接读写 config 目录时无需 sudo。镜像默认值 499/100 适用于无人管理场景;若宿主挂载目录属主与 PUID 不一致,服务端会在日志中报配置目录不可写。

三、前置条件

  1. 宿主已安装 Docker 29.x 与 Compose v2 插件(本例 29.9.2 / v5.6.1 实测通过)。
  2. 准备工作目录与三个数据子目录(路径可按需调整,本文以 /opt/data/quzuo/tmp/lyrion-music-server 为例):
$ mkdir -p config music playlist
$ ls -la
drwxr-xr-x  config
drwxr-xr-x  music
drwxr-xr-x  playlist
  1. music/ 放入待入库的音频文件(本例预置 11 个 mp3/flac/ogg 文件)。目录属主为运行账号,与 PUID/PGID 对齐。
  2. 防火墙放行:3483/tcp、3483/udp、8129/tcp、8130/tcp。3483/udp 是播放器自动发现的通道,漏放行会导致播放器永远不出现,这是该组件部署区别于普通 Web 服务的关键点。

四、部署步骤

4.1 编排文件

工作目录下创建 docker-compose.yml(本文实测采用的原文件):

name: lyrion-9.1.1-stack

services:
  lyrion:
    image: lmscommunity/lyrionmusicserver:9.1.1
    container_name: lyrion-9.1.1-server
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
    ports:
      - "8129:9000"        # Web 管理界面
      - "8130:9090"        # CLI / Telnet 接口
      - "3483:3483/tcp"    # SLIM 协议(播放器 TCP 连接)
      - "3483:3483/udp"    # SLIM 协议(播放器发现)
    volumes:
      - ./config:/config:rw
      - ./music:/music:ro
      - ./playlist:/playlist:rw
    networks:
      - lyrion-net

  player:
    image: giof71/squeezelite:stable-alsa
    container_name: lyrion-9.1.1-player
    environment:
      - SQUEEZELITE_MODE=ALSA
      - SQUEEZELITE_AUDIO_DEVICE=null
      - SQUEEZELITE_SERVER_PORT=lyrion:3483
      - SQUEEZELITE_NAME=G23-TestPlayer
    depends_on:
      - lyrion
    networks:
      - lyrion-net

networks:
  lyrion-net:
    name: lyrion-9.1.1-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.56.0/24

逐段解说:

片段语义
name: lyrion-9.1.1-stack项目名,决定 compose 资源默认前缀
image: lmscommunity/lyrionmusicserver:9.1.1固定版本 tag,避免 latest 漂移
restart: unless-stopped服务器重启后自动拉起,人工 stop 后不自动恢复
PUID=1000 / PGID=1000覆盖镜像默认 499/100,对齐宿主账号
"8129:9000"Web 端口映射到 8129,避开宿主常用 9000
"8130:9090"CLI/telnet 端口映射到 8130
"3483:3483/tcp" 与 "3483:3483/udp"SLIM 协议两个通道分开声明,TCP 承载控制信令,UDP 承载发现广播;本例未改端口,直通
./config:/config:rw配置/缓存/日志持久化,必须 rw
./music:/music:ro曲库只读挂载:服务端只读文件不写回,ro 是防误删的保险
./playlist:/playlist:rw播放列表目录,playlist save 会写文件,必须 rw
SQUEEZELITE_SERVER_PORT=lyrion:3483播放器通过 compose 服务名 lyrion 定位服务端,无需写 IP
SQUEEZELITE_AUDIO_DEVICE=null测试播放器输出到空设备,不占用真实声卡
ipam subnet 10.89.56.0/24固定子网,便于防火墙与多栈共存管理

4.2 启动

$ docker compose up -d
[+] Running 3/3
 ✔ Network lyrion-9.1.1-net     Created
 ✔ Container lyrion-9.1.1-server  Started
 ✔ Container lyrion-9.1.1-player  Started

4.3 验证

第一步,核对两个服务的运行状态与端口映射:

$ docker compose ps
NAME                  IMAGE                                  COMMAND                  SERVICE   CREATED        STATUS          PORTS
lyrion-9.1.1-player   giof71/squeezelite:stable-alsa         "/app/bin/run-squeez…"   player    17 hours ago   Up 29 minutes
lyrion-9.1.1-server   lmscommunity/lyrionmusicserver:9.1.1   "start-container"        lyrion    18 hours ago   Up 18 minutes   0.0.0.0:3483->3483/tcp, 0.0.0.0:3483->3483/udp, [::]:3483->3483/tcp, [::]:3483->3483/udp, 0.0.0.0:8129->9000/tcp, [::]:8129->9000/tcp, 0.0.0.0:8130->9090/tcp, [::]:8130->9090/tcp

四个映射通道全部就位:3483 TCP/UDP、8129→9000、8130→9090。

第二步,验证 Web 界面:

$ curl -I http://127.0.0.1:8129/
HTTP/1.1 302 REDIRECT

返回 302 是正常现象:服务端把根路径重定向到管理首页,浏览器打开 http://<宿主IP>:8129 即可。

第三步,验证 CLI 通道并确认播放器已自动注册(telnet 到 8130,命令以换行结束,回显为 URL 编码形态):

$ telnet 127.0.0.1 8130
version ?
version 9.1.1
players 0
players 0  count%3A2 playerindex%3A0 playerid%3A04%3A53%3A82%3A81%3A67%3A39 uuid%3A ip%3A10.89.56.3%3A49446 name%3AG23-TestPlayer seq_no%3A0 model%3Asqueezelite modelname%3ASqueezeLite power%3A1 isplaying%3A0 displaytype%3Anone isplayer%3A1 canpoweroff%3A1 connected%3A1 firmware%3A2.0.0-1517 ...

count:2 中包含 squeezelite 软件播放器(model:squeezelite,固件 2.0.0-1517),说明播放器已通过 3483 端口完成发现与注册。players 命令的完整字段解读见《Lyrion Music Server 9.1.1 CLI 命令详解》。

第四步,查看播放器容器的注册过程日志:

$ docker logs lyrion-9.1.1-player
Starting squeezelite: /app/bin/squeezelite -N /app/conf/squeezelite-name.txt -n G23-TestPlayer -s lyrion -o null ...
[15:07:26.123] stream_init:535 init stream
[15:07:26.124] output_init_alsa:937 init output
[15:07:26.128] discover_server(720) sending discovery
[15:07:26.129] slimproto_init(220) connecting to lyrion:3483
[15:07:26.130] slimproto_run(562) got HELLO from server

日志显示完整注册链路:发现广播(sending discovery)→ 连接 3483 → 服务端握手(got HELLO)。若此处卡在 discovery 不返回,优先排查 3483/udp 的防火墙与网络互通。

五、数据持久化说明

挂载点宿主目录读写内容实测产物
/config./configrw配置、缓存、日志、收藏prefs/、cache/、logs/ 三个子目录
/music./musicro音频曲库mp3/flac/ogg 源文件
/playlist./playlistrw播放列表文件playlist save 生成的 m3u

/config 目录内的实测结构,备份与迁移围绕它展开:

config/
├── prefs/
│   ├── server.prefs                    # 服务端全部配置(C1 篇详解)
│   ├── log.conf                        # 日志级别配置
│   ├── favorites.opml                  # 收藏夹(OPML 格式)
│   └── clientplaylist_045382816739.m3u # 播放器播放队列快照
├── cache/
│   └── library.db                      # 媒体库 SQLite 数据库(可重建)
└── logs/
    └── server.log                      # 服务端运行日志(排障素材)

持久化要点:

  • 必须备份:prefs/ 全目录与 playlist/ 全目录,体量小、价值高。
  • 可重建:cache/library.db 由扫描生成,损坏后清空目录重新扫描即可恢复,但自定义流派/评分等库内编辑会丢失。
  • 只读边界:music 用 ro 挂载是刻意的——LMS 对曲库只有读需求,ro 可杜绝服务端 bug 或插件误写曲库。个别插件(如自动下载歌词封面到曲库目录)需要写权限时再改 rw,并接受相应风险。

六、环境变量表

6.1 服务端(lmscommunity/lyrionmusicserver:9.1.1)

变量镜像默认本例取值作用实测观察
PUID4991000业务进程 uid,决定挂载目录属主入口脚本按其调整 /config 属主后降权启动
PGID1001000业务进程 gid同上
HTTP_PORT90009000(未改)服务端内部 Web 监听端口进程命令行实测 --httpport 9000
EXTRA_ARGS空未设置追加传给主程序的原始参数进程命令行中保留 $EXTRA_ARGS 位置

实测服务端进程树(ps -ef 节选),可以看到入口脚本的参数组装逻辑:

root       16   1  0 10:24 ?  00:00:00 su squeezeboxserver -s /bin/sh -c /usr/bin/perl /lms/slimserver.pl --prefsdir /config/prefs --logdir /config/logs --cachedir /config/cache --httpport $HTTP_PORT $EXTRA_ARGS
squeeze+   18  17  5 10:24 ?  00:00:59 /usr/bin/perl /lms/slimserver.pl --prefsdir /config/prefs --logdir /config/logs --cachedir /config/cache --httpport 9000

两个信息:一是 --prefsdir/--logdir/--cachedir 三个参数固定指向 /config 下三个子目录,与第五节的挂载设计互为因果;二是 EXTRA_ARGS 原样拼在命令行末尾,需要传非常用参数(如 --noradio、--noupnp)时无需改镜像。

6.2 播放器(giof71/squeezelite:stable-alsa)

变量本例取值作用
SQUEEZELITE_MODEALSA输出后端模式
SQUEEZELITE_AUDIO_DEVICEnullALSA 输出设备,null 为空设备(测试用)
SQUEEZELITE_SERVER_PORTlyrion:3483服务端地址:端口,直接用 compose 服务名
SQUEEZELITE_NAMEG23-TestPlayer播放器显示名,注册后在 Web/CLI 中可见

生产房间实际使用时,把 SQUEEZELITE_AUDIO_DEVICE 换成真实 ALSA 设备(如 hw:CARD=Generic,aplay -l 查询)并按需加 SQUEEZELITE_RATE/SQUEEZELITE_BUFFER 等变量。

七、配置参数说明

部署层参数与运行层配置的分工如下:

层载体典型参数修改方式
部署层docker-compose.yml端口映射、挂载、PUID/PGID、网络改文件后 docker compose up -d 重建
运行层server.prefs媒体库目录、扫描优先级、流媒体超时Web 设置页或 CLI pref 命令,改后即生效或触发重扫

运行层配置的完整参数清单(audiodir、playlistdir、scannerPriority、remotestreamtimeout、日志体系等)在《Lyrion Music Server 9.1.1 配置参数详解》逐项展开。与部署强相关的两条:audiodir 首次部署后必须在 Web 设置中指向 /music(或 CLI pref audiodir /music),否则媒体库为空;playlistdir 指向 /playlist,决定 playlist save 的落盘位置。

八、配置文件挂载

首次启动后,config/prefs/server.prefs 由服务端自动生成,宿主可直接查看:

$ grep -E '^(audiodir|playlistdir|httpport)' config/prefs/server.prefs
audiodir: /music
playlistdir: /playlist
httpport: 9000

注意配置文件里的端口是服务端内部端口(9000),与宿主映射端口(8129)无关;同理配置里的目录路径(/music、/playlist)是容器内路径。理解「配置值 = 容器内视角,端口映射 = 宿主视角」这个双层坐标,是端口类故障排查的基础。

九、等价 docker run 方式

不用 compose 时,以下两条命令与上文编排等价:

$ docker network create --driver bridge --subnet 10.89.56.0/24 lyrion-9.1.1-net

$ docker run -d \
  --name lyrion-9.1.1-server \
  --restart unless-stopped \
  -e PUID=1000 -e PGID=1000 \
  -p 8129:9000 -p 8130:9090 \
  -p 3483:3483/tcp -p 3483:3483/udp \
  -v /opt/data/quzuo/tmp/lyrion-music-server/config:/config:rw \
  -v /opt/data/quzuo/tmp/lyrion-music-server/music:/music:ro \
  -v /opt/data/quzuo/tmp/lyrion-music-server/playlist:/playlist:rw \
  --network lyrion-9.1.1-net \
  lmscommunity/lyrionmusicserver:9.1.1

$ docker run -d \
  --name lyrion-9.1.1-player \
  -e SQUEEZELITE_MODE=ALSA \
  -e SQUEEZELITE_AUDIO_DEVICE=null \
  -e SQUEEZELITE_SERVER_PORT=lyrion:3483 \
  -e SQUEEZELITE_NAME=G23-TestPlayer \
  --network lyrion-9.1.1-net \
  giof71/squeezelite:stable-alsa

两条命令的组合约定与 compose 版本完全一致;--restart unless-stopped 只加在服务端,播放器由人工或独立服务管理即可。

十、常用运维命令

场景命令实测结果
状态总览docker compose ps见 4.3 节回显
服务端日志docker logs --tail 50 lyrion-9.1.1-server滚动输出运行日志
播放器日志docker logs --tail 50 lyrion-9.1.1-player含注册与流连接记录
重启服务端docker restart lyrion-9.1.1-server秒级返回,重启后 Web/CLI 立即可达,播放器自动重连
拉起播放器docker start lyrion-9.1.1-player秒级返回,players 0 重新可见
停止整栈docker compose stop两服务退出,数据卷保留
销毁整栈docker compose down容器与网络删除,宿主三目录数据保留
备份数据tar czf lyrion-bak.tgz config/prefs playlist收敛 prefs 与播放列表两个关键目录

重启类操作后的标准验证序列(全部实测):

$ docker restart lyrion-9.1.1-server
lyrion-9.1.1-server
$ sleep 25 && curl -I http://127.0.0.1:8129/
HTTP/1.1 302 REDIRECT
$ printf 'version ?\n' | timeout 6 nc 127.0.0.1 8130
version 9.1.1

服务端重启约需 15-25 秒完成初始化(首次加载媒体库缓存),期间 Web 与 CLI 可能暂时无响应,属正常现象;播放器端无需任何操作,3483 断连后自动重连注册。

十一、常见问题(排障实录)

11.1 播放器容器 Exited (0):先看退出码再动手

现象:部署完成后数小时检查,docker ps -a 显示 lyrion-9.1.1-player 状态 Exited (0),服务端正常。

排查:

$ docker ps -a --filter name=lyrion-9.1.1-player
lyrion-9.1.1-player   Exited (0)   10 hours ago
$ docker logs --tail 20 lyrion-9.1.1-player
Starting squeezelite: /app/bin/squeezelite -N ... -n G23-TestPlayer -s lyrion -o null ...
(注册日志正常结束,无报错行)

判定:退出码 0 表示干净退出,启动日志无任何异常。squeezelite 作为前台单进程,收到 docker stop 的 SIGTERM 后正常收尾退出,这正是 docker stop 的预期行为(本栈排查时确认对应一次人工停止操作,而非崩溃)。

处置:

$ docker start lyrion-9.1.1-player
lyrion-9.1.1-player
$ docker ps --filter name=lyrion-9.1.1-player
lyrion-9.1.1-player   Up 29 seconds

经验:遇到 Exited 先看退出码——0 优先怀疑人工/编排层停止,非 0 才是崩溃路径,再从日志定位;restart: unless-stopped 对人工 stop 不自动拉起是特性不是缺陷。

11.2 端口映射后本地播放器连不上流(Broken pipe)

现象:在宿主机上直接运行 squeezelite(-s 127.0.0.1 指向映射端口 3483)能完成注册,但下发播放后服务端与播放器之间反复断流,squeezelite 调试日志出现:

[15:47:01.123] stream_sock(589) header: GET /stream.mp3?player=06:53:82:81:67:39
[15:47:01.456] stream_thread(320) read error: Broken pipe

定位:LMS 的播放模型是「服务端主动把音频流推给播放器」,推流地址由服务端按容器内坐标生成(内网地址 + 内部端口 9000)。本例 Web 映射到了宿主 8129,宿主机 9000 无监听,宿主上的播放器按服务端下发的 :9000 地址连流必然失败——注册用的 3483 通了,不代表推流用的 9000 通了。

处置(按场景二选一):

  • 推荐做法:播放器加入同一个 compose 网络(如本例的 player 服务),用服务名直连,推流地址与内网坐标一致,天然无此问题。实测该形态下播放链路完全正常。
  • 变通做法:必须从宿主/其他主机跑 squeezelite 时,把 -s 指向服务端真实可路由地址,并保证该地址的 9000 端口可达(在纯端口映射环境,需把 9000 一并映射到宿主同号端口,即 -p 9000:9000)。

经验:LMS 有两套通道,3483(注册/控制,SLIM 协议)与 9000(音频流,HTTP),排查时分开验证;「注册成功但播不出声」九成是 9000 通道不通。

11.3 曲库文件被移除后统计数与扫描记录不一致

现象:曲库目录中曾预置 11 个文件并完成扫描,其中 tr.mp3 随后被移除;此时 info total songs ? 返回 10,但数据库 scanned_files 表仍能查到 11 条记录。

排查(SQLite 侧核对,库文件位于 config/cache/library.db):

SELECT COUNT(*) FROM tracks;        -- 10
SELECT url FROM scanned_files;      -- 11 条,含 file:///music/tr.mp3

判定:LMS 的设计行为——被移除文件的扫描记录保留为失效条目,不计入曲目总数;下次全量扫描(Web 设置页触发或 CLI rescan)时自动清账。

经验:统计数对不上先核对 scanned_files 与 tracks 两表差异,失效记录不是数据损坏;配合「全量扫描清除失效条目」执行即可。

11.4 首次部署 Web 能开但库为空

现象:部署完成后 Web 首页可访问,但浏览页没有任何专辑/曲目。

定位与处置:镜像不会自动猜曲库路径,首次启动后需在 Web 的「基本设置」把媒体库目录设为 /music(对应挂载),保存时服务端提示执行扫描;确认后观察 config/logs/server.log,出现扫描完成行即入编。CLI 侧可用 rescan(增量)或 wipecache(全量重建)触发,用 info total songs ? 验证结果。

11.5 Web 首页返回 302 不是故障

curl -I http://127.0.0.1:8129/ 返回 HTTP/1.1 302 REDIRECT 是服务端对根路径的标准重定向(目标为管理首页),无需处理;仅当 302 之后的目标页也超时/报错时才需要排查服务端状态。

十二、参考链接