SwingMusic 3.0.0 Docker Compose 部署指南
SwingMusic 3.0.0 的 Docker Compose 从 0 到 1 部署实录:官方镜像选型、曲库挂载、三步初始化向导、持久化重建无损验证、环境变量与六类常见问题排障
SwingMusic 3.0.0 Docker Compose 部署指南
目标:本文讲解如何在服务器上用 Docker Compose 从零部署 SwingMusic 3.0.0 音乐流媒体服务,覆盖镜像选型、曲库挂载、初始化向导、数据持久化、环境变量与升级卸载,全部命令与回显已在 Ubuntu 24.04 实测通过(Compose 项目名 swingmusic-3.0.0-stack,服务端口 8154,曲库 4 首测试音频、2 张专辑、2 位艺术家)。
一、环境信息
- 操作系统:Ubuntu 24.04(x86_64)
- Docker:24.x / Compose v2(
docker compose子命令形态) - SwingMusic:v3.0.0(上游 2026-06-12 发布,部署时 2026-10-30 实查为最新稳定版)
- 镜像:ghcr.io/swingmx/swingmusic:v3.0.0(官方发布,实测镜像体积 1.27 GB,内置 ffmpeg 7.1.4)
- Compose 项目名:swingmusic-3.0.0-stack;服务容器名:swingmusic-3.0.0-app
- 端口:宿主 8154 → 容器内服务端口 1970
- 数据目录:/srv/swingmusic/config(配置与数据库)、/srv/swingmusic/music(曲库)
- 网络:自定义 bridge 网络 swingmusic-3.0.0-net,网段 10.89.62.0/24
- 演示账号:admin / q1w2e3r4
二、镜像选型说明
SwingMusic 官方(swingmx 组织)从 v3.0.0 起直接发布官方镜像 ghcr.io/swingmx/swingmusic,无第三方打包分叉,本文即选官方镜像,理由有三,均为实测结论:
- 官方直出,版本与源码严格对应:镜像 tag 即 SwingMusic 版本号(v3.0.0),digest 可在 GitHub Packages 核对(本文实测 digest sha256:a49155d1809b…);
- 开箱即含转码与 Web 资源:实测镜像内置
/usr/bin/ffmpeg(ffmpeg version 7.1.4-0+deb13u1),按需转码无需自行补依赖;Web 客户端资源随镜像分发,首启自动落到配置目录的 client/ 下; - 配置路径约定清晰:镜像内数据目录固定为 /config 挂载点,首启日志实测打印
Data folder: /config/swingmusic,与本文持久化章节一致。
⚠️ 镜像体积说明:1.27 GB 主要来自 Python 运行时 + ffmpeg + 音频分析依赖(mutagen//aprise 等)+ Web 静态资源,属官方打包策略,无精简官方变体;对体积敏感可自行多阶段构建,但需自行保证 ffmpeg 与字体依赖完整。
三、前置条件
- 服务器已安装 Docker(24+)与 Compose v2 插件,验证:
docker compose version
实测输出:
Docker Compose version v2.39.2
- 端口未被占用。规划宿主端口前先用 ss 检查(本文最初规划 8151,实测该端口已被同机其他服务占用,改用 8154——排障过程见「常见问题」Q1):
ss -ltn | grep -E ':815[0-9] '
实测输出(部署时实测节选,8150–8156 中仅余 8154 空闲可用):
LISTEN 0 4096 0.0.0.0:8150 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8151 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8152 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8153 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8154 0.0.0.0:*
- 曲库目录就绪。没有现成音频时可先用 ffmpeg 生成带 ID3 标签的测试音频(后续向导与检索验证都基于它;ffmpeg 在宿主机或镜像内执行均可,以下为宿主机实测命令):
mkdir -p /srv/swingmusic/music /srv/swingmusic/config
ffmpeg -y -hide_banner -loglevel error -f lavfi -i 'sine=frequency=440:duration=8' \
-af 'afade=t=in:d=1,afade=t=out:st=7:d=1' -codec:a libmp3lame -b:a 192k \
-metadata 'title=Salt Air' -metadata 'artist=Blue Harbor' \
-metadata 'album=Tidal Lines' -metadata 'date=2025' -metadata 'genre=Ambient' \
'/srv/swingmusic/music/Blue Harbor/Tidal Lines/01-Salt Air.mp3'
实测输出(成功时无任何输出,-loglevel error 只报错;用 ls 确认产物):
ls -la '/srv/swingmusic/music/Blue Harbor/Tidal Lines/'
实测输出:
total 416
drwxr-xr-x 2 root root 4096 Oct 30 08:52 .
drwxr-xr-x 3 root root 4096 Oct 30 08:52 ..
-rw-r--r-- 1 root root 193902 Oct 30 08:52 01-Salt Air.mp3
本文曲库共准备 4 首测试音频:Blue Harbor《Tidal Lines》2 首(Salt Air、Sea Glass)+ 秋日山道《晨雾专辑》2 首(晨雾、山间电车),覆盖中英文目录名与多专辑多艺术家场景。
- (可选)自定义网络网段。若服务器上已有一批 bridge 网络,先确认目标网段空闲(本文选 10.89.62.0/24):
docker network ls --format '{{.Name}}' | grep 10.89 || echo 'no custom net matching'
四、部署步骤
4.1 编写 Compose 文件
在 /srv/swingmusic/ 下创建 docker-compose.yml(已实测完整拉起):
name: swingmusic-3.0.0-stack
services:
swingmusic:
image: ghcr.io/swingmx/swingmusic:v3.0.0
container_name: swingmusic-3.0.0-app
ports:
- "8154:1970"
volumes:
- /srv/swingmusic/music:/music
- /srv/swingmusic/config:/config
environment:
- SWINGMUSIC_PORT=1970
- SWINGMUSIC_DEVICE_NAME=swingmusic-lab
networks:
default:
ipv4_address: 10.89.62.10
restart: unless-stopped
networks:
default:
name: swingmusic-3.0.0-net
driver: bridge
ipam:
config:
- subnet: 10.89.62.0/24
配置项逐条说明:
name:Compose 项目名,多套环境并存时用于隔离资源命名;container_name:固定服务容器名,便于后续docker logs/exec直接引用;ports:宿主 8154 → 容器 1970(SwingMusic 固定监听 1970,由镜像内SWINGMUSIC_PORT控制;改端口时保持右侧与之一致即可);volumes:/config 持久化配置文件、双 SQLite 库、封面与艺术家图片、Web 客户端资源与插件;/music 是曲库(换成自己的音频目录时,注意下方 4.4 向导里的目录路径以容器内为准);environment:SWINGMUSIC_PORT与 ports 右值对应;SWINGMUSIC_DEVICE_NAME是设备名,用于移动 App 配对与许可设备标识;networks+ipam:固定网段便于防火墙精确放行;不需要网段管控时整个 networks 段可删(Compose 会自动建默认网络),ipv4_address同理可去;restart: unless-stopped:随宿主开机自启(docker 服务启用前提下),手动 stop 后不再自动拉起。
4.2 拉取镜像
docker pull ghcr.io/swingmx/swingmusic:v3.0.0
实测输出(官方源直连可用,无需代理;重复拉取时回显如下):
v3.0.0: Pulling from swingmx/swingmusic
Digest: sha256:a49155d1809bc6ad09d87d76cc91648c149fc80146b5e10260e70fe1cfa78175
Status: Image is up to date for ghcr.io/swingmx/swingmusic:v3.0.0
4.3 启动服务
cd /srv/swingmusic && docker compose up -d
实测输出:
[+] Running 2/2
✔ Network swingmusic-3.0.0-net Created
✔ Container swingmusic-3.0.0-app Started
4.4 观察首次启动日志
docker logs swingmusic-3.0.0-app 2>&1 | head -25
实测输出(首启扫描 3 首测试音频时):
[95mSwing Music v3.0.0 (PID: 1) [0m
Server running on:
[92mhttp://0.0.0.0:1970[0m
[92mhttp://127.0.0.1:1970[0m
[93mData folder: /config/swingmusic[0m
[INFO] Websockets are not supported on WSGI, ignoring
[INFO] Starting granian (main PID: 1)
[INFO] Listening at: http://0.0.0.0:1970
[INFO] Spawning worker-1 with PID: 8
Loading tracks... Done!
Loading albums... Done!
Loading artists... Done!
[INFO] Started worker-1
INFO|Batch 1/1 ...
Completed batch 1/1: 3 files indexed
3 new files indexed
Done
关键行解读:Data folder: /config/swingmusic 确认配置落点与挂载一致;Starting granian 是实际承载 HTTP 的 WSGI 服务器;Completed batch 1/1: 3 files indexed 是首个扫描批次的入库结果(本文曲库初版 3 首,后续增量验证见 4.7)。日志开头的 Assets dir could not be found 为无害告警,不影响功能。
4.5 初始化向导(首次部署必经)
浏览器打开 http://<服务器IP>:8154,首次部署会进入三步初始化向导:
- 创建管理员:设置管理员用户名与密码(本文用 admin / q1w2e3r4),对应后端接口
POST /auth/profile/create; - 选择曲库目录:向导列出容器内可挂载的目录,勾选 /music(对应接口
POST /notsettings/add-root-dirs,提交后自动触发全量扫描); - 等待扫描完成:向导轮询初始化状态接口直至扫描批次清零。
向导进度可通过状态接口随时核对(免登录可达):
curl -s http://localhost:8154/onboarding-data
实测输出(向导完成后):
{"adminExists":true,"onboardingComplete":true,"rootDirsSet":true,"scanMessage":"","userHome":"/music"}
字段解读:adminExists 管理员已创建;rootDirsSet 曲库根目录已设置;onboardingComplete 向导整体完成;scanMessage 显示当前扫描批次进度(扫描中形如 scan_batch_cleared: 1/1,完成后清空)。向导完成后刷新页面即进入登录页,用 admin / q1w2e3r4 登录。
4.6 验证服务
探活:
curl -s -o /dev/null -w 'GET / -> %{http_code}\n' http://localhost:8154/
实测输出:
GET / -> 200
登录并确认曲库入库(4 首测试音频、2 张专辑):
curl -s -X POST http://localhost:8154/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' -c /tmp/sm-ck.txt -o /dev/null -w 'login -> %{http_code}\n'
curl -s -b /tmp/sm-ck.txt 'http://localhost:8154/getall/albums?start=0' \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('albums:', d['total'], [i['title'] for i in d['items']])"
实测输出:
login -> 200
albums: 2 ['Tidal Lines', '晨雾专辑']
4.7 (验证)新增曲目与增量扫描
部署完放新歌不需要重建服务:把音频放进曲库目录后触发一次扫描即可。实测生成第 4 首测试音频后手动触发:
curl -s -b /tmp/sm-ck.txt http://localhost:8154/notsettings/trigger-scan
实测输出:
{"msg":"Scan triggered!"}
随后复查专辑曲目数(Tidal Lines 从 1 首变 2 首,新曲目 Sea Glass 可被检索命中),增量行为逐条实测记录见《SwingMusic 3.0.0 配置参数详解》扫描一节;也可开启周期扫描(enablePeriodicScans)免除手动触发。
五、数据持久化说明
SwingMusic 的全部可变数据都落在 /config 与 /music 两个挂载内,备份这两个目录即可完成整机备份。实测重建服务(down 后重新 up)后配置、账号、曲库数据完整无损:
| 路径(容器内) | 宿主路径 | 内容 | 备份策略 |
|---|---|---|---|
| /config/swingmusic/settings.json | /srv/swingmusic/config/swingmusic/settings.json | 全部运行参数(曲库目录、扫描、艺术家拆分等) | 变更时备份 |
| /config/swingmusic/private.key | 同上目录 | JWT 签名密钥(serverId 派生),删了会导致全部登录态失效 | 必须随库备份 |
| /config/swingmusic/swingmusic.db(+wal/shm) | 同上目录 | 曲库元数据库(专辑/艺术家/曲目/文件夹) | 每日增量或快照 |
| /config/swingmusic/images/ | 同上目录 | 提取的专辑封面与艺术家图片(webp) | 可再生,低优先级 |
| /config/swingmusic/plugins/、client/ | 同上目录 | 插件配置、Web 客户端静态资源 | 随版本自动更新,可不备份 |
| /music/ | /srv/swingmusic/music/ | 音频原文件 | 与曲库同源,另行备份 |
数据库备份建议在服务停止或空闲时冷拷贝(SQLite 单文件最稳;wal/shm 两个伴生文件一并拷贝):
cd /srv/swingmusic && docker compose stop swingmusic \
&& cp -a config/swingmusic/swingmusic.db* backup/ \
&& docker compose start swingmusic
实测输出(节选):
Container swingmusic-3.0.0-app Stopped
Container swingmusic-3.0.0-app Started
重建无损验证实录:docker compose down 删除容器与网络后重新 up -d,登录接口与曲库列表实测完全一致(albums: 2 ['Tidal Lines', '晨雾专辑']),登录 Cookie 也因 private.key 持久化而继续有效,无需重新登录。
六、环境变量表
| 变量 | 官方镜像默认 | 说明 | 实测表现 |
|---|---|---|---|
| SWINGMUSIC_PORT | 1970 | 服务监听端口 | 与 ports 右值一致即可,日志回显 http://0.0.0.0:1970 |
| SWINGMUSIC_DEVICE_NAME | 宿主名派生 | 设备名,用于移动 App 配对与许可设备识别 | 实测设为 swingmusic-lab 后管理接口回显 deviceName: swingmusic-lab |
| SWINGMUSIC_CONFIG_DIR | 未设 | 配置目录父路径(镜像内约定用 /config 挂载点) | 镜像内以 HOME=/music、数据目录 /config/swingmusic 的约定工作,一般无需设置 |
| SWINGMUSIC_CLIENT_DIR | 未设 | 自定义 Web 客户端资源目录 | 仅自托管前端构建产物时使用 |
💡 说明:镜像内置了
SWINGMUSIC_IN_DOCKER=1与HOME=/music两个内部变量(实测env回显),前者供程序判断部署形态、后者使默认家目录落在曲库挂载点(向导状态接口回显userHome: /music即由此而来);两者均无需手动设置。SwingMusic 的业务参数(曲库、扫描、艺术家拆分等)不在环境变量层控制,一律收敛到 settings.json(详见《SwingMusic 3.0.0 配置参数详解》)。
七、配置参数说明
首启后配置落在 /srv/swingmusic/config/swingmusic/settings.json,全部 30 余个键的逐项含义、默认值与改法见《SwingMusic 3.0.0 配置参数详解》。与部署直接相关的三件事:
- 曲库目录:settings.json 的
rootDirs数组(容器内路径),首启用向导设置,后续可在 Web 设置页改,改完自动触发重扫; - 扫描节奏:
enablePeriodicScans(默认关)+scanInterval(默认 10 分钟)+enableWatchdog(默认关),家庭曲库低频更新场景建议开周期扫描; - 运行时改参:无需重启——Web 设置页的每次修改都会实时写回 settings.json 并按需重建内存索引(实测
scanInterval: 10等值与文件内容一致)。
八、配置文件挂载
本文只挂载两个目录:/music(曲库,只读使用亦可,SwingMusic 不改写音频文件,仅读元数据与内嵌封面)与 /config(全部可变数据)。若想把 settings.json 纳入版本管理,可再加一行单文件挂载:
volumes:
- /srv/swingmusic/music:/music
- /srv/swingmusic/config:/config
单文件直挂 settings.json 不推荐:首启时该文件尚不存在,目录挂载才能保证首启自动生成。首启后如需以文件方式改参,改完重启生效:
cd /srv/swingmusic && docker compose restart
九、等价 docker run
与第四章 Compose 完全等价的单命令形态(不愿用 Compose 时可直跑):
docker run -d \
--name swingmusic-3.0.0-app \
-p 8154:1970 \
-e SWINGMUSIC_PORT=1970 \
-e SWINGMUSIC_DEVICE_NAME=swingmusic-lab \
-v /srv/swingmusic/music:/music \
-v /srv/swingmusic/config:/config \
--restart unless-stopped \
ghcr.io/swingmx/swingmusic:v3.0.0
启动后验证与 4.6 相同(GET / -> 200 即健康)。
十、常用运维命令
状态与日志:
docker compose ps
实测输出:
NAME STATUS PORTS
swingmusic-3.0.0-app Up 6 seconds 0.0.0.0:8154->1970/tcp, [::]:8154->1970/tcp
docker compose logs -f --tail 30
实测输出(跟踪扫描进度时的关键行):
INFO|Batch 1/1 ...
Completed batch 1/1: 1 files indexed
1 new files indexed
Done
资源占用:
docker stats --no-stream --format '{{.Name}} CPU={{.CPUPerc}} MEM={{.MemUsage}}' swingmusic-3.0.0-app
实测输出:
swingmusic-3.0.0-app CPU=0.13% MEM=64.5MiB / 15.57GiB
重启/停止/卸载:
docker compose restart # 重启服务(改 settings.json 后用)
docker compose stop # 停止,保留容器
docker compose down # 停止并删除容器与网络(数据在宿主目录,不受影响)
down 实测输出:
[+] Running 2/2
✔ Container swingmusic-3.0.0-app Removed
✔ Network swingmusic-3.0.0-net Removed
升级流程(以未来发布新版本为例):改镜像 tag → 拉取 → 重建:
sed -i 's/v3.0.0/v3.0.1/' /srv/swingmusic/docker-compose.yml
docker compose pull && docker compose up -d
回滚同理把 tag 改回 v3.0.0。升级前后用程序自带参数核对版本(镜像内实测回显):
docker exec swingmusic-3.0.0-app swingmusic --version
实测输出:
swingmusic v3.0.0
忘记管理员密码时,用自带的重置工具(镜像内实测):
docker exec swingmusic-3.0.0-app swingmusic --password-reset
按提示输入用户名与新密码即可,重置后用新密码登录验证。
十一、常见问题(FAQ)
Q1:宿主端口被占用?
现象:docker compose up -d 报 bind 失败,或规划端口探测时发现已监听。实测本文最初规划 8151 时发现已被同机其他服务占用:
LISTEN 0 4096 0.0.0.0:8151 0.0.0.0:*
解决:ss -ltn 重扫空闲端口(本文改用 8154),改 Compose 的 ports 左值后重新 up -d。右侧 1970 永远不变。
Q2:往曲库放了新歌但界面上没有?
现象:文件已拷入 /music,专辑列表不更新。原因:默认 enablePeriodicScans: false 且无看门狗,SwingMusic 不会自动发现新文件。解决:任选其一——Web 设置页点扫描(等价 GET /notsettings/trigger-scan,实测回显 {"msg":"Scan triggered!"});或开周期扫描;或开看门狗。参数含义见《SwingMusic 3.0.0 配置参数详解》扫描一节。
Q3:重建服务后要重新登录吗?
实测不需要:JWT 签名密钥由 settings.json 的 serverId 派生且 private.key 随 /config 持久化,down 后重新 up -d,原登录 Cookie 实测继续可用(登录接口与曲库列表逐项复查一致)。若删除了 /config/swingmusic/private.key 或整个配置目录,则所有登录态失效,需走初始化向导重建。
Q4:首启日志出现 Assets dir could not be found 告警?
无害告警:程序按默认路径找内置资源未命中后改用镜像内约定路径,Web 资源实际落盘 /config/swingmusic/client/(实测目录存在且页面 200),可忽略。
Q5:中文艺术家/专辑目录名会不会扫不出来? 不会。实测含中文目录《秋日山道/晨雾专辑》的 2 首音频完整入库,检索「晨雾」命中(评分 60.87),专辑与艺术家页均正常展示。仅文件系统需支持 UTF-8(主流 Linux 发行版默认即满足)。
Q6:服务端口能改成 80/443 对外吗? 可以但不建议直改:改法是 ports 左值换成宿主 80/443(右值 1970 不动)。生产对外建议前置 Nginx/Caddy 反向代理加 TLS——Web 与 API 均为 HTTP,反向代理层终止 TLS 即可,程序内无需额外配置。
十二、参考链接
- 官方仓库:https://github.com/swingmx/swingmusic
- 官方镜像:https://github.com/swingmx/swingmusic/pkgs/container/swingmusic (ghcr.io/swingmx/swingmusic)
- 一键安装脚本(非部署形态):https://setup.swingmx.com
- 发布页:https://github.com/swingmx/swingmusic/releases (v3.0.0,2026-06-12)
- 站内延伸:《SwingMusic 3.0.0 介绍与选型指南》、《mStream 6.32.0 Docker Compose 部署指南》、《Navidrome 0.64.2 Docker Compose 部署指南》