Audiobookshelf 2.37.2 Docker Compose 部署实战
Audiobookshelf 2.37.2 官方 Compose 部署全流程实测:四挂载点编排、PORT 默认 3333 与基础路径 /audiobookshelf 两大默认值避坑、init 建号、建库扫描、HLS 播放验证、SSRF 白名单接入自建播客源、首份备份与升级回滚,附 4 案例排障实录(2026-10-27 实测)。
Audiobookshelf 2.37.2 Docker Compose 部署实战
目标:在一台 Linux 服务器上,用官方 Compose 编排把 Audiobookshelf 2.37.2 从零部署到「初始化 root → 建立有声书库与播客库 → 扫描入库 → 播放验证 → 出第一份备份」的全链路可用状态。本文所有命令输入与输出均来自 2026-10-27 的真实部署实测(4 核 8 GB 虚拟机、Debian 系发行版、Docker Compose v2),包括一次「端口映射通了却连不上」的真实故障与两处极易踩坑的官方默认值(服务默认监听 3333、默认挂载基础路径
/audiobookshelf)。与本文配套的选型分析见《Audiobookshelf 2.37.2 介绍与选型指南》,参数级配置见《Audiobookshelf 2.37.2 配置参数详解》,API 与运维自动化见《Audiobookshelf 2.37.2 常用 API 与运维实战》。
一、环境信息
本篇为实测篇,全部数据来自一台真实 Linux 服务器的部署过程回显:
| 项目 | 值 |
|---|---|
| 实测日期 | 2026-10-27 |
| 服务器系统 | Linux(Debian 系,4 核 8 GB 虚拟机) |
| 编排工具 | Docker Compose v2(docker compose version 实测可用) |
| 部署产物 | 官方发行镜像 advplyr/audiobookshelf:2.37.2(单服务编排) |
| 服务版本 | 2.37.2(官方最新稳定版,2026-10-23 发布) |
| 宿主端口 | 8137(ss -ltn 核实未占用后选定) |
| 编排网络 | 自建 bridge 网络 audiobookshelf-2.37.2-net,显式 --subnet 10.89.60.0/24 |
| 初始账号 | root / q1w2e3r4(实测创建) |
| 媒体目录 | /opt/data/audiobooks(有声书,2 本书共 3 个音频文件)、/opt/data/podcasts(播客目录 + 本地 RSS 测试源) |
💡 说明:编排与命令中的路径(如
/opt/data/...)是这台实测服务器的目录规划,读者部署时替换为自己的数据盘路径即可;本文保证的是「命令 → 回显」的真实性与可复现性。
二、部署方案总览
2.1 形态选择
Audiobookshelf 官方提供两种生产形态:Debian 系发行版的 apt 软件包(带 systemd 单元)与官方发行镜像(Compose 编排是官方文档的首选路径)。本篇选 Compose 形态,理由:升级回滚是「改一行版本号 + 一条命令」、数据目录边界清晰、便于与播客测试源等辅助服务组网。镜像标签策略上固定 2.37.2 而非 latest,保证本文回显可复现。
2.2 前置准备清单
- 端口:计划映射宿主 8137 → 服务端口 13378。先核实端口空闲:
ss -ltn | grep 8137 || echo "8137 free"
实测回显(端口空闲时只输出第二行):
8137 free
- 媒体目录:规划两个内容目录与两个数据目录,职责划分遵循官方约定:
| 挂载点 | 用途 | 读写要求 |
|---|---|---|
/audiobooks | 有声书媒体文件 | 建议只读挂载(:ro),服务零侵入引用 |
/podcasts | 播客目录(订阅下载落地) | 读写(下载单集要写盘) |
/config | 业务数据库(absdatabase.sqlite)+ 迁移脚本 | 读写,必须持久化 |
/metadata | 元数据缓存、日志、转码流临时目录、备份产物 | 读写,必须持久化 |
⚠️ 避坑:
/config存着全部用户、库结构与播放进度(SQLite 单库absdatabase.sqlite),丢了它等于丢掉整站「记忆」;/metadata下的backups/是内置备份的落盘位置。两者都要落在明确持久化的宿主目录上。
- 网络:从空闲网段取一个显式子网(避免与既有网络冲突)。先查看已占网段:
docker network ls
docker network inspect <已有网络名> --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
本例选定 10.89.60.0/24(规划前已核实 10.89.56–75 段内未被占用)。
三、编写编排文件
在部署目录(本例 /opt/data/audiobookshelf)创建 docker-compose.yml:
name: audiobookshelf-2.37.2-stack
services:
audiobookshelf:
image: advplyr/audiobookshelf:2.37.2
container_name: audiobookshelf-2.37.2-main
ports:
- "8137:13378"
volumes:
- /opt/data/audiobookshelf/config:/config
- /opt/data/audiobookshelf/metadata:/metadata
- /opt/data/audiobooks:/audiobooks:ro
- /opt/data/podcasts:/podcasts
environment:
- TZ=Asia/Shanghai
- PORT=13378
networks:
- abs-net
restart: unless-stopped
networks:
abs-net:
name: audiobookshelf-2.37.2-net
driver: bridge
ipam:
config:
- subnet: 10.89.60.0/24
四个关键点:
PORT=13378必须显式设置。这是本次实测踩到的最大的坑——官方镜像在未设置PORT时不监听 13378,而是落到服务源码的默认端口 3333(源码index.js:const PORT = options.port || process.env.PORT || 3333)。如果照搬「8137:13378的端口映射却不设 PORT」,映射会指向一个没有进程监听的端口,服务日志看起来一切正常但外部永远连不上。详见第八节案例 1。- 服务默认工作在
/audiobookshelf基础路径下。源码默认值ROUTER_BASE_PATH ?? '/audiobookshelf',即根路径访问会由服务侧跳转到/audiobookshelf/。局域网直连场景不需要改它,反代场景按《Audiobookshelf 2.37.2 配置参数详解》统一规划。 - 有声书目录挂载为
:ro(只读)。Audiobookshelf 对媒体文件是引用式管理,扫描与播放都不需要写媒体盘,只读挂载可以防误删。 name:指定编排名(audiobookshelf-2.37.2-stack),便于后续docker compose按名管理。
四、启动与初始化
4.1 启动
cd /opt/data/audiobookshelf
docker compose up -d
docker compose ps
实测回显:
[+] Running 2/2
✔ Network audiobookshelf-2.37.2-net Created
✔ Container audiobookshelf-2.37.2-main Started
NAME IMAGE STATUS PORTS
audiobookshelf-2.37.2-main advplyr/audiobookshelf:2.37.2 Up 4 seconds 0.0.0.0:8137->13378/tcp, [::]:8137->13378/tcp
启动日志(docker compose logs audiobookshelf | head)中的关键三行:
[2026-10-27 23:47:07.904] INFO: [Watcher] Initializing watcher for "有声书图书馆".
[2026-10-27 23:47:07.910] INFO: Listening on port :13378
[2026-10-27 23:47:07.915] INFO: [Watcher] "有声书图书馆" Ready
以及官方日志中的服务路径声明:
[2026-10-27 23:47:07.885] INFO: [Server] Serving from base path "/audiobookshelf"
4.2 健康检查
curl -s http://127.0.0.1:8137/ping
实测回显:
{"success":true}
再看初始化状态:
curl -s http://127.0.0.1:8137/status
实测回显(首次启动时 isInit 为 false,完成初始化后如下):
{"app":"audiobookshelf","serverVersion":"2.37.2","isInit":true,"language":"zh-cn","authMethods":["local"],"authFormData":{"authLoginCustomMessage":""}}
两个探针端点在根路径与基础路径下均可达(实测 /ping、/audiobookshelf/ping 都返回 200),用哪个做健康检查都可以。
4.3 初始化 root 账号
浏览器访问 http://<服务器IP>:8137,会跳入初始化向导:设置 root 用户名与密码(本例 root / q1w2e3r4),随后进入「新建库」页面。
API 等效操作(便于脚本化部署)——POST /init 创建 root:
curl -s -X POST http://127.0.0.1:8137/init \
-H 'Content-Type: application/json' \
-d '{"newRoot":{"username":"root","password":"q1w2e3r4"}}' \
-w '\nHTTP %{http_code}\n'
实测回显:
{"user":{"id":"da78502d-603d-4a89-835e-48c2bd409761","username":"root",...}}
HTTP 200
登录拿访问令牌(后续 API 全部要用):
curl -s -X POST http://127.0.0.1:8137/login \
-H 'Content-Type: application/json' \
-d '{"username":"root","password":"q1w2e3r4"}' \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('user:', d['user']['username'], '| type:', d['user']['type'])"
实测回显:
user: root | type: root
⚠️ 避坑:root 只能初始化一次。对已初始化的服务重复调用
POST /init会被拒绝,实测返回 HTTP 500,服务端日志记录ERROR: [Server] attempt to init server when server already has a root user。数据目录复用时(迁移、重建编排)不会重新进入初始化向导,这是正常行为。
五、建库与扫描验证
5.1 建有声书库
用刚拿到的令牌创建「有声书」类型库,指向 /audiobooks(编排中已挂载,服务内路径):
TOKEN="<登录返回的 user.token>"
curl -s -X POST http://127.0.0.1:8137/api/libraries \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"有声书图书馆","icon":"audiobook","mediaType":"book","provider":"audible","folders":[{"fullPath":"/audiobooks"}]}' \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('library:', d['name'], '| mediaType:', d['mediaType'], '| id:', d['id'])"
实测回显:
library: 有声书图书馆 | mediaType: book | id: d14e4bba-d24e-4e41-8761-ffb76851b4c1
创建库时服务端立即执行首轮扫描。实测目录里 2 本书被识别:
curl -s "http://127.0.0.1:8137/api/libraries/d14e4bba-d24e-4e41-8761-ffb76851b4c1/items" \
-H "Authorization: Bearer $TOKEN" \
| python3 -c "
import json,sys
d=json.load(sys.stdin)
print('total:', d['total'])
for it in d['results']:
print('-', it['media']['metadata']['title'], '|', it['media']['metadata'].get('authorName'))
"
实测回显:
total: 2
- 三体系列:地球往事 | 刘慈欣
- 自托管实践指南(测试音频) | 演示作者
5.2 播放验证
对任一条目创建播放会话并请求 HLS 播放列表:
ITEM=f9b0678e-xxxx-xxxx-xxxx-xxxxxxxxxxxx # 条目 id,来自上一步列表
curl -s -X POST "http://127.0.0.1:8137/api/items/$ITEM/play" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"deviceInfo":{"deviceId":"doc-demo"}}' > /tmp/play.json
SID=$(python3 -c "import json; print(json.load(open('/tmp/play.json'))['id'])")
curl -s -o /dev/null -w 'HLS playlist: %{http_code}\n' "http://127.0.0.1:8137/hls/$SID/output.m3u8" -H "Authorization: Bearer $TOKEN"
实测回显:
HLS playlist: 200
播放列表拉到 200,浏览器打开 http://<服务器IP>:8137 进入条目页点播放即可听到声音;手机 App 填同一地址与账号即可同步进度。播放会话的进度同步与关闭接口详见《Audiobookshelf 2.37.2 常用 API 与运维实战》。
5.3 播客库与本地 RSS 测试源(可选进阶)
播客库的建立与有声书库同型(mediaType 换成 podcast,目录挂 /podcasts)。播客的「订阅源」依赖服务端出网抓取 RSS——这里有一个实测踩到的硬性安全限制:服务端默认拒绝抓取解析到私网地址的订阅源(内置 SSRF 防护),并在 Web 端「添加播客」时直接报「Call to 10.89.60.2 is blocked」类错误。
局域网自建 RSS 源(如测试用、或内网播客分发)需要两步:
- 给测试源服务一个可解析的网络别名(订阅源 URL 里写的主机名必须能被服务端解析,短别名要显式注册,见第八节案例 4);
- 在编排中把该主机名加入官方提供的 SSRF 白名单环境变量(详见《Audiobookshelf 2.37.2 配置参数详解》):
environment:
- PORT=13378
- SSRF_REQUEST_FILTER_WHITELIST=podcast-source
重启编排后,服务日志会出现白名单生效的确认行:
[2026-10-27 23:47:07.726] INFO: [Server] SSRF Request Filter Whitelisting: podcast-source
之后「添加播客 → 填订阅源 URL → 预检 → 建立」一路畅通,实测订阅本机 RSS 源并成功下载单集(/podcasts/<播客名>/第02期:媒体库命名规范.mp3 落盘,条目页出现已下载单集)。
六、第一份备份
初始化与建库完成后立即出一份备份,验证备份链路:
curl -s -X POST http://127.0.0.1:8137/api/backups -H "Authorization: Bearer $TOKEN" -w '\nHTTP %{http_code}\n'
实测回显(截取):
{"backups":[{"id":"2026-10-27T2356","key":"sqlite","backupDirPath":"/metadata/backups",...,"filename":"2026-10-27T2356.audiobookshelf","fileSize":17108,"serverVersion":"2.37.2"}]}
HTTP 200
备份文件落在了编排挂载的 /metadata/backups/ 下(宿主对应 /opt/data/audiobookshelf/metadata/backups/2026-10-27T2356.audiobookshelf,实测 17108 字节)。定时备份与保留份数在管理端「设置 → 备份」里配置,命令行改法见《Audiobookshelf 2.37.2 配置参数详解》。
七、版本升级与回滚
- 升级:把
docker-compose.yml里的镜像标签换成新版本号(如2.37.2→ 之后的版本),依次执行docker compose pull && docker compose up -d。数据库 schema 由服务内置迁移机制处理(/config/migrations/目录即迁移脚本,实测存在)。 - 回滚:把标签改回旧版本再
up -d。注意官方不支持跨大版本的数据库「降级」迁移——回滚前先做一次手动备份(POST /api/backups),最坏情况用备份文件恢复/config。 - 升级前:先
curl http://127.0.0.1:8137/status确认当前serverVersion,升级完成后再查一次确认生效。
八、排障实录
以下 4 个案例全部来自本次部署实测,按「现象 → 定位 → 根因 → 处置」沉淀。
案例 1:端口映射正常,服务却连不上(PORT 默认值)
- 现象:
docker compose ps显示0.0.0.0:8137->13378/tcp映射正常,启动日志无报错,但curl http://127.0.0.1:8137/ping无响应。 - 定位:编排里没有显式设置
PORT环境变量。查官方镜像源码index.js:
const PORT = options.port || process.env.PORT || 3333;
const ROUTER_BASE_PATH = process.env.ROUTER_BASE_PATH ?? '/audiobookshelf';
- 根因:Audiobookshelf 服务源码的默认监听端口是 3333 而非 13378。只写
8137:13378映射时,宿主 8137 转发的 13378 上没有任何进程。 - 处置:编排
environment加PORT=13378(或把映射改成8137:3333,但官方文档的约定端口是 13378,建议跟随)。重启后日志出现Listening on port :13378,探针立刻可达。 - 教训:涉及「官方镜像 + 端口」时,以「映射端口 = 服务实际监听端口」双向核对为准,不要默认镜像行为与文档端口号一致。
案例 2:地址栏多了一层 /audiobookshelf(基础路径默认值)
- 现象:启动日志明确输出
Serving from base path "/audiobookshelf",浏览器访问根路径时被服务侧引导到/audiobookshelf/。 - 根因:2.37.2 服务源码的默认基础路径是
/audiobookshelf(ROUTER_BASE_PATH ?? '/audiobookshelf'),这是官方默认行为而非故障。v2.37.2 发行说明同时明确:该变量自本版起自动规范化(补前导斜杠、去尾斜杠),写audiobookshelf或/audiobookshelf/都会收敛为/audiobookshelf。 - 处置:局域网直连场景保持默认即可(书签直接用带路径的地址);需要根路径直达时,显式设置
ROUTER_BASE_PATH=/覆盖默认值,反代场景的完整配法见配置参数篇。
案例 3:添加私网播客订阅源被拦(SSRF 防护)
- 现象:Web 端「添加播客」提交局域网 RSS 地址后报错,服务端日志记录
Call to 10.89.60.2 is blocked。 - 定位:这是官方内置的 SSRF 请求过滤器在拦「解析到私网/环回地址」的出网请求,不是网络不通(从服务端
curl测试源是通的)。 - 处置:私网自建订阅源需要把源主机名写入
SSRF_REQUEST_FILTER_WHITELIST(逗号分隔多个)或以DISABLE_SSRF_REQUEST_FILTER=1整体关闭(不推荐,除非确信无 SSRF 风险)。实测加白名单并重启后,同一订阅源预检即通过(HTTP 200,返回解析出的标题与单集列表)。 - 教训:「服务端能通」不等于「服务愿意出网」,遇到自建源被拦先查应用层的 SSRF 策略再查网络。
案例 4:订阅源主机名解析失败(EAI_AGAIN)
- 现象:加了白名单后预检仍失败,服务端日志出现
getaddrinfo EAI_AGAIN podcast-source。 - 定位:编排内自建的 RSS 源用了短主机名
podcast-source,但该名字没有注册进编排网络——网络内没有可解析的短别名,服务端 DNS 查询超时(EAI_AGAIN 是解析超时典型错误码)。 - 处置:给源服务注册网络别名(Compose 里写
networks: [abs-net]并加aliases: [podcast-source],等效的命令行形式是--network-alias podcast-source),重启后解析即通。实测解析成功后,同一 URL 的预检、订阅、单集下载全链路成功。 - 教训:编排内服务互访时,URL 里的主机名必须与网络内注册的别名一致;用长名字(服务全名)通常天然可解析,短名要显式注册。
九、常见问题 FAQ
Q1:服务已经初始化过,重建编排后还要再跑 /init 吗?
不需要,只要 /config 挂载还是原来的目录,root 与库结构都在,直接登录即可。重复初始化会被拒绝(实测 HTTP 500)。
Q2:媒体文件放在挂载之外(宿主其他目录)能扫到吗?
扫不到。服务只能访问编排中声明的挂载路径,新建库时也只会列出 /audiobooks、/podcasts 这类已挂载目录。加目录 = 编排加挂载 + up -d 重建。
Q3:为什么推荐媒体目录只读挂载?
有声书库对媒体文件是纯引用式管理(读文件、封面与缓存写 /metadata),:ro 不影响功能,还能防止误操作改写原始音频文件。播客目录例外——订阅下载的单集要落盘,必须可写。
Q4:升级版本后页面打不开/端口不通了?
先看启动日志有没有 Listening on port 与版本号输出,再核对 PORT 与 ROUTER_BASE_PATH 两个环境变量是否被编排改动覆盖。这两个默认值是实测中最容易翻车的两处。
Q5:怎么验证备份可用?
/metadata/backups/ 下出现 .audiobookshelf 文件即备份成功;恢复演练可在测试目录挂载空 /config 后按官方恢复流程导入备份文件,核对用户与库是否还原。
十、本篇小结
- 官方 Compose 单服务编排 + 四挂载点(内容两目录 +
/config+/metadata)是 Audiobookshelf 的标准部署形态;/config与/metadata必须持久化。 - 两个官方默认值必须心里有数:未设
PORT时服务监听 3333;默认基础路径为/audiobookshelf。 - 部署闭环:
up -d→/ping//status探活 →POST /init建 root →POST /api/libraries建库扫描 → 播放会话 200 →POST /api/backups出第一份备份。 - 私网自建播客源 = 网络别名注册 +
SSRF_REQUEST_FILTER_WHITELIST白名单,二者缺一不可。
十一、参考链接
- 官方安装文档(Compose 与 Debian 包):https://www.audiobookshelf.org/install
- 官方 Docker 镜像:https://github.com/advplyr/audiobookshelf/pkgs/container/audiobookshelf
- v2.37.2 发行说明(ROUTER_BASE_PATH 规范化等):https://github.com/advplyr/audiobookshelf/releases/tag/v2.37.2
- 站内系列:《Audiobookshelf 2.37.2 介绍与选型指南》《Audiobookshelf 2.37.2 配置参数详解》《Audiobookshelf 2.37.2 常用 API 与运维实战》