Audioserve Docker Compose 部署实战
Audioserve 0.30.1 Docker Compose 实测部署:镜像准备与目录规划、编排文件逐项解读、启动初始化回显、认证与 API/转码/章节链路冒烟、播放位置备份恢复、升级运维与四则排障实录。
Audioserve Docker Compose 部署实战
目标:在一台 Linux 服务器上用 Docker Compose 把 Audioserve(Rust 轻量有声书/音频流媒体服务器)跑起来,覆盖镜像准备、目录规划、编排文件、启动初始化、Web 与 API 冒烟、转码链路验证、播放位置备份/恢复与排障实录。组件背景与选型逻辑见《Audioserve 介绍与选型指南》,全部命令与回显来自 2026-10-28 真实服务器实测。
一、环境信息
实测环境与约定(真实服务器视角,宿主机为 Ubuntu,内核 7.0.0-38-generic):
| 项目 | 取值 |
|---|---|
| 实测日期 | 2026-10-28 |
| 宿主 Docker | Docker version 29.9.2, build a82e528 |
| 镜像 | izderadicka/audioserve:latest(构建于 2026-05-23,amd64,237.9 MB,内部即 v0.30.1) |
| 服务端口 | 宿主 8138 → 容器 3000(Audioserve 默认监听 0.0.0.0:3000) |
| 音频目录 | 宿主 ./audio 以只读方式挂载为容器 /audiobooks |
| 数据目录 | 宿主 ./data 挂载为容器 /home/audioserve/.audioserve(缓存/密钥/进度落盘处) |
| Docker 网络 | compose 项目自定义网络,显式指定 10.89.57.0/24(避开宿主与其他项目已占网段) |
| 示例凭据 | 共享密钥 q1w2e3r4(生产请替换为不少于 14 字符的强密钥,官方安全基线要求) |
Compose 编排文件名固定为 docker-compose.yml,项目名(顶层 name:)固定为 audioserve-0.30.1-stack。
二、软件与镜像准备
Audioserve 官方提供 Docker 镜像 izderadicka/audioserve,latest 标签即最新稳定构建,另有每日自动构建的 unstable 标签。拉取与镜像指纹确认:
docker pull izderadicka/audioserve:latest
回显(2026-10-28 实测):
latest: Pulling from izderadicka/audioserve
Digest: sha256:aac13420d5ef2cf322fdffecd49108708b82096d6a04b1db88ec7e7e9fc39fb3
Status: Downloaded newer image for izderadicka/audioserve:latest
docker.io/izderadicka/audioserve:latest
镜像关键事实(docker inspect 实测):
Created=2026-05-23T07:08:57.790941716Z Size=237865772 Arch=amd64 OS=linux
Entrypoint=["./audioserve"] Config.Cmd=null
RepoDigest=izderadicka/audioserve@sha256:aac13420d5ef2cf322fdffecd49108708b82096d6a04b1db88ec7e7e9fc39fb3
- 工作目录
/audioserve,内含主程序audioserve与 Web 客户端目录client/dist(官方 PWA 客户端已打进镜像,无需单独部署前端); - 内置 ffmpeg 8.0.1(转码开箱可用),镜像内运行用户为 uid 1000;
- 入口点就是主程序本身、无默认 CMD,因此 compose 的
command必须给出完整参数列表(含末尾音频目录/audiobooks)。
三、目录规划与 Compose 编排
/opt/audioserve/
├── docker-compose.yml # 编排文件
├── audio/ # 音频库(按 作者/书名/章节 组织,挂载为只读)
│ ├── Clark, Arthur C./2001 A Space Odyssey/001 - Chapter 1.mp3 ...
│ ├── Clark, Arthur C./Rendezvous with Rama/CD1, CD2/
│ ├── Adams, Douglas/The Hitchhiker's Guide to the Galaxy/
│ └── Wells, H. G./The Time Machine/The Time Machine.m4b
└── data/ # 服务数据(密钥/集合缓存/图标缓存/进度备份)
测试音频库用 ffmpeg 自造(正弦音调 mp3 与带章节元数据的 m4b),结构遵循官方 README 推荐的「作者 Last Name, First Name/书名/数字前缀章节文件」。关键前置:镜像内进程以 uid 1000 运行,宿主 data/ 目录必须对该 uid 可写,否则启动失败(排障实录第 1 条):
mkdir -p /opt/audioserve/data && chown 1000:1000 /opt/audioserve/data
docker-compose.yml 全文(实测版本):
name: audioserve-0.30.1-stack
services:
audioserve:
image: izderadicka/audioserve:latest
container_name: audioserve-0.30.1-main
restart: unless-stopped
command: ["--tags", "--positions-backup-file", "/home/audioserve/.audioserve/positions-backup.json", "--positions-backup-schedule", "0 3 * * *", "/audiobooks"]
environment:
- AUDIOSERVE_SHARED_SECRET=q1w2e3r4
ports:
- "8138:3000"
volumes:
- ./audio:/audiobooks:ro
- ./data:/home/audioserve/.audioserve
networks:
- audioserve-net
networks:
audioserve-net:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.89.57.0/24
要点解读:
command:传入命令行参数。--tags开启音频元数据标签展示;--positions-backup-file+--positions-backup-schedule让播放进度每小时定期落盘 JSON(cron 表达式示例0 3 * * *为每天 03:00);末尾/audiobooks声明音频库集合;- 共享密钥用环境变量
AUDIOSERVE_SHARED_SECRET注入而不写进命令行(避免出现在进程列表里); - 音频目录挂载为
:ro只读——流服务器只需要读权限,写权限交给data/; - 显式
name:与自定义网络子网,避免多项目并存时 compose 自动命名与网段冲突。
四、启动与初始化
docker compose up -d
启动日志(docker logs audioserve-0.30.1-main,逐行照抄实测回显):
[2026-10-28T09:33:11Z INFO audioserve] Started audioserve 0.30.1 #561370e (22.05.2026 01:40:12) with features async-tar, async-zip, behind-proxy, chrono, cron, default, folder-download, shared-positions, symlinks, tls, websock
[2026-10-28T09:33:11Z INFO audioserve] Server listening on 0.0.0.0:3000
[2026-10-28T09:33:11Z INFO collection::cache] Quick scan for collection "/audiobooks" finished
三行分别是版本与编译特性横幅(folder-download 目录打包下载、shared-positions 播放位置共享、tls 内置证书、websock 进度同步等均在列)、监听地址、集合快速扫描完成。按官方 Collections cache 章节说明:首次启动做全量扫描建立缓存,此后启动走基于已存元数据的快速核对,秒级就绪——与实测日志中的 Quick scan ... finished 一致。
docker compose ps 回显:
NAME IMAGE STATUS PORTS
audioserve-0.30.1-main izderadicka/audioserve:latest Up 7 minutes 0.0.0.0:8138->3000/tcp, [::]:8138->3000/tcp
初始化完成后 data/ 目录内容(ls -la 实测,属主为容器内 uid 1000):
-rw------- 32 audioserve.secret # 共享密钥的本地盐值哈希(服务端生成,600 权限)
drwxr-xr-x 3 col_db # sled 集合缓存数据库(实测约 540 KB)
drwxr-xr-x 4 icons-cache # Web 客户端封面图标缓存
-rw-r--r-- 171 positions-backup.json # 播放位置备份(配置了 --positions-backup-file 后出现)
五、Web 与 API 冒烟
Web 客户端:浏览器访问 http://<服务器IP>:8138/,输入共享密钥 q1w2e3r4 即进入音频库。curl 冒烟:
curl -s http://127.0.0.1:8138/ | head -3
回显:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
...
<title>Audioserve Web Client</title>
认证换 token:REST API 全部需要签名 token。客户端拿共享密钥换取 token——简单模式直接传明文密钥,官方推荐的防重放模式是加盐 SHA-256(客户端生成随机盐 + sha256(密钥+盐) 一并提交)。简单模式实测:
curl -s -w '\nHTTP %{http_code}\n' -X POST http://127.0.0.1:8138/authenticate \
-H 'Content-Type: application/json' \
-d '{"secret":"q1w2e3r4"}'
回显(token 为服务端签发的不透明随机串,实际约 176 字符,此处截断展示):
wTebv5s4icRVc4mWoTQX1s9FnIZ79tEAG7BwJGWmngwAAAAAbMLwuhvfO/aYka9z4NxBHDcsU5nDymzpjyCgX3XIl+uldnOv…
HTTP 200
token 有效期默认一年(--token-validity-days 可调),客户端把它放进 Authorization: Bearer 请求头或 audioserve_token cookie 即可。错误密钥实测(返回 401):
curl -s -w '\nHTTP %{http_code}\n' -X POST http://127.0.0.1:8138/authenticate \
-H 'Content-Type: application/json' -d '{"secret":"AAAA|BBBB"}'
{"error":"Unauthorized","details":"Authentication failed"}
HTTP 401
带 token 访问集合元数据端点(后续所有 API 都带 Authorization: Bearer <token>,也可改用 cookie audioserve_token):
curl -s http://127.0.0.1:8138/collections/ -H "Authorization: Bearer $TOKEN"
回显(节选,data/ 实测值):
{
"version": "0.30.1",
"commit": "561370e (22.05.2026 01:40:12)",
"folder_download": true,
"shared_positions": true,
"count": 1,
"names": ["audiobooks"]
}
六、核心功能验证
目录浏览(API 是磁盘目录树的服务端视图,按集合编号寻址 /0/folder/<路径>,路径需 URL 编码):
curl -s 'http://127.0.0.1:8138/0/folder/Clark%2C%20Arthur%20C.%2F2001%20A%20Space%20Odyssey' \
-H "Authorization: Bearer $TOKEN"
回显(实测):
{
"is_file": false,
"is_collapsed": false,
"modified": 1793178392613,
"total_time": 180,
"files": [
{"name": "001 - Chapter 1.mp3",
"path": "Clark, Arthur C./2001 A Space Odyssey/001 - Chapter 1.mp3",
"meta": {"duration": 60, "bitrate": 64, "tags": null},
"mime": "audio/mpeg", "section": null},
{"name": "002 - Chapter 2.mp3",
"path": "Clark, Arthur C./2001 A Space Odyssey/002 - Chapter 2.mp3",
"meta": {"duration": 60, "bitrate": 64, "tags": null},
"mime": "audio/mpeg", "section": null},
{"name": "003 - Chapter 3.mp3",
"path": "Clark, Arthur C./2001 A Space Odyssey/003 - Chapter 3.mp3",
"meta": {"duration": 60, "bitrate": 64, "tags": null},
"mime": "audio/mpeg", "section": null}
],
"subfolders": [],
"cover": {"path": "Clark, Arthur C./2001 A Space Odyssey/cover.png", "mime": "image/png"},
"description": {"path": "Clark, Arthur C./2001 A Space Odyssey/description.txt", "mime": "text/plain"},
"tags": null
}
要点:total_time 是全书总时长(秒);files[].meta 由二进制内置 libavformat 解出(时长/码率/标签),与目录内第一张图片(封面)、第一个文本文件(简介)自动关联;子目录在 subfolders 中返回(CD1/CD2 这类即在此呈现)。
搜索(基于集合缓存的目录名搜索,/0/search?q=,files 与 subfolders 两组列表返回命中项,可含匹配目录内的文件):
curl -s 'http://127.0.0.1:8138/0/search?q=clark' -H "Authorization: Bearer $TOKEN"
回显(实测,q=clark 同一关键词命中 Clark, Arthur C. 与后补的 Clarke, Arthur C. New 两个目录,可见匹配为子串包含):
{
"files": [],
"subfolders": [
{"name": "Clark, Arthur C.", "modified": 1793178391877, "path": "Clark, Arthur C.", "is_file": false, "finished": false},
{"name": "Clarke, Arthur C. New", "modified": 1793179081450, "path": "Clarke, Arthur C. New", "is_file": false, "finished": false}
]
}
流式回放与转码(?trans= 三档默认 Opus in Ogg:l=32k / m=48k / h=64k):
P1="Clark%2C%20Arthur%20C.%2F2001%20A%20Space%20Odyssey%2F001%20-%20Chapter%201.mp3"
curl -s -o /dev/null -w 'raw HTTP %{http_code} type=%{content_type} size=%{size_download}\n' \
"http://127.0.0.1:8138/0/audio/$P1" -H "Authorization: Bearer $TOKEN"
curl -s -o /dev/null -w 'trans=l HTTP %{http_code} type=%{content_type} size=%{size_download}\n' \
"http://127.0.0.1:8138/0/audio/$P1?trans=l" -H "Authorization: Bearer $TOKEN"
curl -s -o /dev/null -w 'trans=m HTTP %{http_code} type=%{content_type} size=%{size_download}\n' \
"http://127.0.0.1:8138/0/audio/$P1?trans=m" -H "Authorization: Bearer $TOKEN"
curl -s -o /dev/null -w 'trans=h HTTP %{http_code} type=%{content_type} size=%{size_download}\n' \
"http://127.0.0.1:8138/0/audio/$P1?trans=h" -H "Authorization: Bearer $TOKEN"
回显(60 秒 64k mp3 源文件,三种取流方式对比):
raw HTTP 200 type=audio/mpeg size=480487
trans=l HTTP 200 type=audio/ogg size=253962
trans=m HTTP 200 type=audio/ogg size=475797
trans=h HTTP 200 type=audio/ogg size=607560
拖动续播依赖的 HTTP Range 实测(返回 206 分段):
curl -s -o /dev/null -w 'HTTP %{http_code} size=%{size_download}\n' -H 'Range: bytes=0-1023' \
"http://127.0.0.1:8138/0/audio/$P1" -H "Authorization: Bearer $TOKEN"
HTTP 206 size=1024
有声书专项(同库实测):
.m4b章节书:The Time Machine.m4b的章节以原始路径$$章节号$$起止$$后缀形式呈现为虚拟文件,可按章取流(返回audio/aac);.chaptersCSV 章节文件:003 - Long Story.mp3(25 分钟无章节 mp3)配同名003 - Long Story.mp3.chaptersCSV 后,目录接口会返回虚拟子文件夹呈现三个章节;- 整目录打包下载:
/0/download/<目录路径>返回application/zip(实测 1.4 MB,测试库整体打包)。
七、播放位置备份与恢复
Audioserve 的"每设备听到哪了"存在 data/col_db 内嵌键值库中,多设备按"设备组"共享(/positions/<group> API,POST 写入、GET 读取、/last 取最新,实测写读均 200)。跨机迁移/备份走官方 JSON 备份机制,compose 中已配置:
command: ["--positions-backup-file", "/home/audioserve/.audioserve/positions-backup.json",
"--positions-backup-schedule", "0 3 * * *", "/audiobooks"]
除定时任务外,可随时向进程发 SIGUSR2 强制立即备份(实测):
docker exec audioserve-0.30.1-main kill -USR2 1
cat data/positions-backup.json
回显(cat data/positions-backup.json,实测——顶层按集合路径分组,其下按目录路径、设备组嵌套):
{"/audiobooks":{"Clark, Arthur C./2001 A Space Odyssey":{"demo-group":{"file":"001 - Chapter 1.mp3","timestamp":1793179051575,"position":42.5,"folder_finished":false}}}
}
恢复:新机器上把 JSON 放回数据目录,启动时加 --positions-restore=v1。实测发现恢复流程是一次性的——服务导入完成即打印 Positions restoration is finished, exiting program, restart it now without --positions-restore arg 并退出;若 compose 里保留了该参数且配置了 restart: unless-stopped,容器会陷入"启动→恢复→退出→再启动"的循环。正确操作是:加上参数 docker compose up -d 等日志出现 restored/finished 字样 → 移除参数再 docker compose up -d。
整机备份清单(Docker 形态的全部状态就这三样):
audio/音频库本体;data/服务数据(含audioserve.secret——它是共享密钥的校验盐值,丢了会导致所有旧 token 失效,需重登录;迁移时随col_db一起拷贝);positions-backup.json进度备份(可选,作为 col_db 的快照冗余)。
八、升级运维
- 官方发版节奏为不定期 tag,镜像
latest跟随稳定版;升级即docker compose pull && docker compose up -d,数据目录格式向后兼容(col_db为 sled,无手工迁移); - 想尝鲜换
image: izderadicka/audioserve:unstable(每日构建),回滚改回latest再up -d; - 新增/修改音频目录无需重启:集合缓存默认开启 inotify 监听,变更约 10 秒防抖后自动进入索引(实测新建目录投递 mp3 后约 13 秒内可被搜索命中);大面积重组目录后可
docker compose restart触发全量扫描; - 修改 compose 参数(如转码配置、端口)后
docker compose up -d会自动重建容器,数据无损。
九、排障实录
以下四条均为本次实测中真实发生、真实定位的问题:
1. 启动即失败:Error creating/reading secret: Permission denied (os error 13)
现象:容器反复退出,日志只有一行 Error。原因:镜像内进程以 uid 1000 运行,宿主 data/ 目录若由 root 创建且未放权,uid 1000 无法写 audioserve.secret。定位与修复:
ls -ln data/ # 数字 UID 直观暴露属主问题
chown 1000:1000 data/ && docker compose up -d
日志中权限修复前后的真实对照(复现时逐行照抄):
[INFO audioserve] Started audioserve 0.30.1 #561370e (22.05.2026 01:40:12) with features async-tar, ...
Error: Error creating/reading secret: Permission denied (os error 13)
同理,音频库只读挂载即可(无需写权限),但必须保证 uid 1000 可读:宿主侧 chmod -R o+r 或 chown -R 1000。
2. docker compose up 报 Bind for 0.0.0.0:8129 failed: port is already allocated
原因:宿主端口被其他进程/容器占用。实测复现的 daemon 报错原文:
docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint ... Bind for 0.0.0.0:8138 failed: port is already allocated
处理:ss -ltnp | grep 8138 找到占用者后换宿主端口(只改映射左侧,如 "8139:3000"),或停掉占用进程。多项目共存时建议在规划期用 ss -ltn 核对端口表。
3. 认证 401:{"error":"Unauthorized","details":"Authentication failed"}
三类常见成因,按概率排序:密钥打错(共享密钥区分大小写);环境变量与客户端输入不一致(AUDIOSERVE_SHARED_SECRET 改动后客户端用旧密钥);时间偏差过大(token 为带过期时间的签名值,服务器时间漂移会提前判过期)。本次实测中前两类都复现过(错误密钥稳定 401),可用 /collections/ 端点快速二分——401 在认证层,404 在资源层。
4. 新放入的音频搜不到 / 目录不显示
集合缓存有约 10 秒防抖窗口(日志可见 with debounce 10 secs),投递新目录后稍等即可;若长时间未出现,优先检查 docker logs 中是否有目录扫描报错(如符号链接默认不跟随——需 --allow-symlinks),仍不行则 docker compose restart 触发全量重扫(缓存重建只读盘无风险)。
十、参考链接
- 官方 README(部署与安全基线):https://github.com/izderadicka/audioserve#readme
- 官方快速安全部署指南:https://github.com/izderadicka/audioserve/blob/master/docs/deploy.md
- Docker Hub 镜像页:https://hub.docker.com/r/izderadicka/audioserve
- Releases(版本与 unstable 说明):https://github.com/izderadicka/audioserve/releases
- API 文档:https://github.com/izderadicka/audioserve/blob/master/docs/api.md
- 本专栏姊妹篇:《Audioserve 介绍与选型指南》(https://www.quzuo.net/document/MeqWm6L3TUWt )、《Audioserve 配置参数详解》、《Audioserve 常用命令与运维实战(核心篇)》