Snapcast 0.35.0 Docker Compose 部署指南
基于官方 deb 本地构建镜像的 Snapcast 0.35.0 三节点 Compose 编排:镜像选型查证、端口与配置挂载、datadir 持久化实测、等价 docker run 与运维命令全回显。
Snapcast 0.35.0 Docker Compose 部署指南
目标:在一台 Linux 服务器上用 Docker Compose 编排「1 个 snapserver + 2 个 snapclient」的多房间同步音频栈,完成镜像构建、端口映射、配置挂载与持久化验证。已在 Docker 29.9.2 / Compose v5.6.1 环境实测 Snapcast 0.35.0 三节点拓扑部署与重启恢复通过。
一、环境信息
本文所有命令与回显均在以下实测环境采集:
- 宿主系统:Debian GNU/Linux 12 (bookworm),x86_64
- Docker:29.9.2(build a82e528),Docker Compose:v5.6.1
- Snapcast:v0.35.0 (rev f1237347),服务器与客户端均基于官方 deb(bookworm amd64)构建本地镜像
- 拓扑:
snapcast-server(映射 8151→1704、8152→1705、8153→1780)+client1+client2,同一自定义网络snapcast-0.35.0-net(10.89.61.0/24) - 音源:
pipe:///serverdata/snapfifo(流名SineTest,44100:16:2,codec=pcm),由宿主侧脚本持续写入 - 客户端输出:无声卡环境,
--soundcard null丢弃采样验证同步链路 - 实测数据日期:2026-10-30
二、镜像选型说明
选择镜像前先核对官方发行渠道,逐项结论如下(2026-10-30 实查):
| 渠道 | 结论 | 依据 |
|---|---|---|
| Docker Hub 官方镜像 | 无官方发布 | 官方文档 doc/install.md、doc/build.md 通篇无 Docker 安装指引(raw.githubusercontent.com 实查无命中),官方推荐 deb/PPA/源码编译 |
| GitHub Releases deb 包 | 本文采用 | v0.35.0 提供 46 个资产,覆盖 bookworm/bullseye/trixie × amd64/arm64/armhf × 标准/with-pulse/with-pipewire 三种后端 |
| 第三方社区镜像 | 不推荐 | 无法保证版本与构建透明度,多房间音频栈组件间版本耦合(协议 v2、JSON-RPC v23),应自行从官方 deb 构建 |
💡 说明:snapserver 与 snapclient 的通信协议有版本号(实测
snapclient协议版本 2、JSON-RPC 版本 23.0.0),服务器与客户端必须同源构建。从同一 v0.35.0 deb 构建两个本地镜像可彻底锁定版本一致性,这也是本文不使用任何现成镜像的原因。
三、前置条件
- Docker 24+ 与 Docker Compose v2+ 已安装(
docker compose version可执行); - 以下端口在宿主机未被占用:8151、8152、8153(映射容器内 1704/1705/1780);
- 准备约 300MB 磁盘空间(两个镜像各约 100~200MB,含 debian:bookworm-slim 基础层);
- 已下载 v0.35.0 官方 deb:
mkdir -p /opt/snapcast/debs && cd /opt/snapcast/debs
wget https://github.com/snapcast/snapcast/releases/download/v0.35.0/snapserver_0.35.0-1_amd64_bookworm.deb
wget https://github.com/snapcast/snapcast/releases/download/v0.35.0/snapclient_0.35.0-1_amd64_bookworm.deb
⚠️ 注意:GitHub Releases 下载慢或不通时,可走代理(
curl -x http://192.168.1.62:7897 -LO <URL>)或从国内镜像加速站获取同版本 deb;deb 完整性以 Release 页 sha256 为准。
四、部署步骤
4.1 目录与文件准备
规划目录结构(配置、数据、构建上下文分离):
/opt/snapcast/
├── compose.yml
├── debs/
│ ├── snapserver_0.35.0-1_amd64_bookworm.deb
│ └── snapclient_0.35.0-1_amd64_bookworm.deb
├── docker/
│ ├── Dockerfile.snapserver
│ └── Dockerfile.snapclient
└── serverdata/
├── snapserver.conf
└── snapfifo # 命名管道,首次启动后由 snapserver 自动创建
4.2 构建服务器与客户端镜像
两个 Dockerfile 均以 debian:bookworm-slim 为基座,直接安装官方 deb,保证与裸机 deb 安装行为完全一致(含 snapserver/snapclient 运行账号与 audio 组)。
docker/Dockerfile.snapserver:
FROM debian:bookworm-slim
COPY debs/snapserver_0.35.0-1_amd64_bookworm.deb /tmp/snapserver.deb
RUN apt-get update \
&& apt-get install -y --no-install-recommends /tmp/snapserver.deb \
&& rm -rf /var/lib/apt/lists/* /tmp/*.deb
EXPOSE 1704 1705 1780
ENTRYPOINT ["/usr/bin/snapserver"]
CMD ["-c", "/etc/snapserver.conf"]
docker/Dockerfile.snapclient:
FROM debian:bookworm-slim
COPY debs/snapclient_0.35.0-1_amd64_bookworm.deb /tmp/snapclient.deb
RUN apt-get update \
&& apt-get install -y --no-install-recommends /tmp/snapclient.deb \
&& rm -rf /var/lib/apt/lists/* /tmp/*.deb
ENTRYPOINT ["/usr/bin/snapclient"]
在 /opt/snapcast 下构建(输出节选,实测):
docker build -f docker/Dockerfile.snapserver -t snapcast-server-0.35.0:local .
docker build -f docker/Dockerfile.snapclient -t snapcast-client-0.35.0:local .
#8 exporting layers done
#8 exporting manifest sha256:cb20ac9f71c5b791abdffd99403fd1f67cb9b5cf0d4ab87e8ed7b2eb3cab805b done
#8 exporting config sha256:0b002a78c811f24cb48fe51abe7859dabac3edbd1fb755d01ba53c90e579b747 done
#8 naming to docker.io/library/snapcast-server-0.35.0:local done
#8 unpacking to docker.io/library/snapcast-server-0.35.0:local done
#8 DONE 0.1s
#8 naming to docker.io/library/snapcast-client-0.35.0:local done
#8 unpacking to docker.io/library/snapcast-client-0.35.0:local done
#8 DONE 0.1s
验证镜像已生成:
docker images | grep snapcast
snapcast-client-0.35.0 local a8f4fa7c9325 5 minutes ago 122MB
snapcast-server-0.35.0 local ecf9cf84d95b 6 minutes ago 152MB
4.3 编写 compose.yml
在 /opt/snapcast/compose.yml 写入以下编排(本文实测原样使用):
name: snapcast-0.35.0-stack
services:
server:
image: snapcast-server-0.35.0:local
hostname: snapserver
ports:
- "8151:1704"
- "8152:1705"
- "8153:1780"
volumes:
- ./serverdata/snapserver.conf:/etc/snapserver.conf
- ./serverdata:/serverdata
networks: [snapnet]
restart: unless-stopped
client1:
image: snapcast-client-0.35.0:local
command: ["tcp://server:1704", "--soundcard", "null", "--latency", "0"]
depends_on: [server]
networks: [snapnet]
restart: unless-stopped
client2:
image: snapcast-client-0.35.0:local
command: ["tcp://server:1704", "--soundcard", "null", "--latency", "0"]
depends_on: [server]
networks: [snapnet]
restart: unless-stopped
networks:
snapnet:
name: snapcast-0.35.0-net
driver: bridge
ipam:
config:
- subnet: 10.89.61.0/24
编排要点逐项说明:
hostname: snapserver:容器网络内 DNS 名,客户端命令里的tcp://server:1704依赖 Compose 服务名解析,两套机制都能解析到 server;8151/8152/8153 → 1704/1705/1780:1704 音频流、1705 TCP 控制台、1780 HTTP 控制台;宿主侧端口按空闲段自定,改左侧即可;./serverdata/snapserver.conf:/etc/snapserver.conf:配置文件单文件挂载,改配置无需重建镜像;./serverdata:/serverdata:目录挂载,pipe 源的snapfifo与服务器持久化数据经此与宿主交换;command: [... "--soundcard", "null" ...]:无声卡环境的关键参数,丢弃采样但完整走同步链路;restart: unless-stopped:服务器与客户端进程崩溃自动拉起(与官方 systemd 单元Restart=on-failure行为对齐);- 固定
subnet 10.89.61.0/24:固定网段便于防火墙按源放行,非必需。
4.4 启动与验证
cd /opt/snapcast
docker compose up -d
实测回显(首次启动):
[+] Running 4/4
✔ Network snapcast-0.35.0-net Created
✔ Container snapcast-0.35.0-server Started
✔ Container snapcast-0.35.0-client1 Started
✔ Container snapcast-0.35.0-client2 Started
确认运行状态:
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
snapcast-0.35.0-client1 snapcast-client-0.35.0:local "/usr/bin/snapclient…" client1 26 minutes ago Up 26 minutes
snapcast-0.35.0-client2 snapcast-client-0.35.0:local "/usr/bin/snapclient…" client2 26 minutes ago Up 26 minutes
snapcast-0.35.0-server snapcast-server-0.35.0:local "/usr/bin/snapserver…" server 26 minutes ago Up 21 minutes 0.0.0.0:8151->1704/tcp, [::]:8151->1704/tcp, 0.0.0.0:8152->1705/tcp, [::]:8152->1705/tcp, 0.0.0.0:8153->1780/tcp, [::]:8153->1780/tcp
查看服务器启动日志,确认三个端口监听与 pipe 源创建(输出节选,实测):
docker compose logs server | head -12
snapcast-0.35.0-server | 2026-10-30 00-51-59.023 [Info] (Snapserver) Version 0.35.0, revision f1237347
snapcast-0.35.0-server | 2026-10-30 00-51-59.023 [Info] (Snapserver) Adding source: pipe:///serverdata/snapfifo?name=SineTest&sampleformat=44100:16:2
snapcast-0.35.0-server | 2026-10-30 00-51-59.025 [Info] (PipeStream) PipeStream mode: create
snapcast-0.35.0-server | 2026-10-30 00-51-59.025 [Info] (ControlServer) Creating TCP control acceptor for address: ::, port: 1705
snapcast-0.35.0-server | 2026-10-30 00-51-59.025 [Info] (ControlServer) Creating HTTP acceptor for address: ::, port: 1780
snapcast-0.35.0-server | 2026-10-30 00-51-59.025 [Info] (StreamServer) Creating TCP stream acceptor for address: ::, port: 1704
通过 HTTP 控制台验证客户端接入(无声卡客户端以 null 设备完成同步链路验证):
curl -s http://127.0.0.1:8153/jsonrpc -H 'Content-Type: application/json' \
-d '{"id":2,"jsonrpc":"2.0","method":"Server.GetStatus"}'
实测回显(节选,两客户端 connected: true,流 playing):
{
"id": 2,
"jsonrpc": "2.0",
"result": {
"server": {
"groups": [
{
"clients": [
{
"connected": true,
"id": "86:4c:86:eb:df:d7",
"snapclient": {
"protocolVersion": 2,
"version": "0.35.0"
}
},
{
"connected": true,
"id": "1e:66:50:a2:56:b7"
}
],
"muted": false,
"stream_id": "SineTest"
}
],
"streams": [
{
"id": "SineTest",
"status": "playing",
"uri": {
"raw": "pipe:///serverdata/snapfifo?chunk_ms=20&codec=pcm&name=SineTest&sampleformat=44100%3A16%3A2",
"scheme": "pipe"
}
}
]
}
}
}
最后喂入音源完成端到端验证——往命名管道持续写 PCM(示例为 440Hz 正弦波生成器,也可以是 MPD 等上游的 pipe 输出):
# 宿主机执行;fifo 经目录挂载与容器内 /serverdata/snapfifo 为同一文件
python3 -c "
import math, struct, sys
fifo = sys.argv[1]; phase = 0.0; RATE = 44100
f = open(fifo, 'wb', buffering=0)
while True:
frames = bytearray()
for i in range(4410):
v = int(20000 * math.sin(2 * math.pi * 440.0 * (phase + i) / RATE))
frames += struct.pack('<hh', v, v)
phase = (phase + 4410) % RATE
f.write(bytes(frames))
" /opt/snapcast/serverdata/snapfifo
五、数据持久化说明
5.1 需要持久化的数据
Snapcast 服务器有两类状态需要区分:
| 数据 | 位置 | 内容 | 不持久化的后果 |
|---|---|---|---|
| 客户端拓扑配置 | /var/lib/snapserver/server.json([server] datadir) | 客户端名字、音量、静音、分组、延迟 | 服务器重启后全部回到默认 |
| 音频管道与本地文件 | pipe:// 源路径(本文 /serverdata/snapfifo) | 上游写入的实时 PCM | 管道本身无需持久化,重启后按 mode=create 自动重建 |
5.2 持久化实测结论
本文按 4.3 的 compose(未挂载 /var/lib/snapserver)实测一次完整的重建验证:
# 重启前给客户端命名
curl -s http://127.0.0.1:8153/jsonrpc -H 'Content-Type: application/json' \
-d '{"id":1,"jsonrpc":"2.0","method":"Client.SetName","params":{"id":"66:5f:2e:b8:5e:7f","name":"TestPersist"}}'
{"id":1,"jsonrpc":"2.0","result":{"name":"TestPersist"}}
# 一键重建
docker compose down && docker compose up -d
Container snapcast-0.35.0-server Removed
Network snapcast-0.35.0-net Removing
Network snapcast-0.35.0-net Removed
Container snapcast-0.35.0-client2 Started
Container snapcast-0.35.0-client1 Started
重启后查询状态(节选,实测):
streams: [('SineTest', 'playing')]
client: 86:4c:86:eb:df:d7 | connected: True | name: '' | vol: 100
client: 1e:66:50:a2:56:b7 | connected: True | name: '' | vol: 100
两条实测结论:
- 未挂载 datadir 时客户端配置不持久化:重启前命名的
TestPersist重启后消失(name: ''),因为 snapserver 重启后没有从server.json恢复; - 客户端身份随容器重建而变:snapclient 以本机 MAC 作为唯一 ID,容器重建生成新随机 MAC(旧
66:5f:2e:...变为86:4c:86:...),旧客户端记录残留为connected: false(可用Server.DeleteClient清理)。生产中若需稳定身份,为每个 client 服务显式指定--hostID(如--hostID client1)。
5.3 生产持久化 compose 片段
生产环境给 server 增加两条挂载(client 不需要):
server:
volumes:
- ./serverdata/snapserver.conf:/etc/snapserver.conf
- ./serverdata:/serverdata
- ./serverdata/lib:/var/lib/snapserver
💡 说明:
./serverdata/lib对应容器内datadir默认值/var/lib/snapserver/(daemon 模式),server.json会落在宿主机serverdata/lib/下,重建容器后名字/音量/分组原样恢复。[server] datadir也可显式指定其他路径,与挂载点保持一致即可。
六、环境变量表
snapserver/snapclient 官方 deb 无约定的环境变量配置面(配置走 /etc/snapserver.conf 与命令行),Compose 编排下常用注入点如下:
| 变量/注入点 | 适用服务 | 作用 | 示例 |
|---|---|---|---|
command(数组) | client1/client2 | 传递 snapclient 命令行参数 | ["tcp://server:1704", "--soundcard", "null"] |
command(数组) | server | 覆盖默认 ["-c", "/etc/snapserver.conf"],可追加任意 --server.* 选项 | ["-c", "/etc/snapserver.conf", "--server.mdns_enabled=false"] |
TZ | 全部 | 时区(影响日志时间戳显示) | Asia/Shanghai |
http_proxy/https_proxy | 构建期 | apt 拉取依赖走代理 | 构建时 --build-arg 或 Docker 全局代理 |
💡 说明:snapclient 的所有命令行选项见
snapclient --help(全文已沉淀于站内《Snapcast 0.35.0 常用 CLI 命令与工具详解》);snapserver 的-hh选项与/etc/snapserver.conf配置段的对应关系见站内《Snapcast 0.35.0 配置参数详解》——每个配置文件选项都有等价命令行形式--<section>.<name>=<value>。
七、配置参数说明
本文编排中三个服务涉及的配置分三层:
- 服务器运行配置(
serverdata/snapserver.conf,单文件挂载到/etc/snapserver.conf):
[stream]
source = pipe:///serverdata/snapfifo?name=SineTest&sampleformat=44100:16:2
codec = pcm
chunk_ms = 20
buffer = 1000
send_to_muted = false
[tcp-streaming]
enabled = true
port = 1704
[tcp-control]
enabled = true
port = 1705
[http]
enabled = true
port = 1780
逐项说明:
source:音源 URI。pipe:///serverdata/snapfifo指向挂载目录内的命名管道(mode缺省即create,服务器启动时自动创建);name=SineTest是流在控制接口里的 ID;sampleformat=44100:16:2固定采样格式(采样率:位深:声道);codec = pcm:不编码原样透传,CPU 零开销;家庭内网建议保持官方默认flac(codec 四选对比见站内《Snapcast 0.35.0 配置参数详解》5.2 节);chunk_ms = 20:每次从源读取并编码的时间片(毫秒),默认 20;buffer = 1000:端到端同步缓冲(毫秒),越大越抗网络抖动、操作时延越高;send_to_muted = false:静音客户端不再推流(省带宽),改为true可实现「静音后取消静音即出声」的零延迟切换;[tcp-streaming]/[tcp-control]/[http]:三个监听面开关与端口,与 compose 端口映射一一对应。
-
客户端运行参数(compose
command):tcp://server:1704服务器地址、--soundcard null输出设备、--latency 0声卡固有延迟补偿(毫秒)。 -
编排层参数(compose.yml):端口映射、网络、重启策略,见 4.3 的逐项说明。
八、配置文件挂载
Compose 配置挂载的完整对应关系(宿主机路径以 /opt/snapcast 为前缀):
| 宿主机路径 | 容器内路径 | 模式 | 用途 |
|---|---|---|---|
./serverdata/snapserver.conf | /etc/snapserver.conf | 单文件 ro 建议改为 rw | 服务器主配置(deb 默认读取路径) |
./serverdata/ | /serverdata | rw | pipe 源命名管道 + 自定义 datadir 等数据 |
./serverdata/lib/ | /var/lib/snapserver(5.3 增配) | rw | server.json 客户端拓扑持久化 |
修改配置后的生效方式:snapserver.conf 变更需重启 server 服务(docker compose restart server),客户端 command 变更需要重建(docker compose up -d --force-recreate client1);命名管道文件与配置文件均在宿主机,docker compose down/up 不会丢失。
九、等价 docker run
不经 Compose 时,以下三条命令与本文编排完全等价(先建网络,再逐个启动):
docker network create --driver bridge --subnet 10.89.61.0/24 snapcast-0.35.0-net
docker run -d --name snapcast-0.35.0-server \
--hostname snapserver \
--network snapcast-0.35.0-net \
-p 8151:1704 -p 8152:1705 -p 8153:1780 \
-v /opt/snapcast/serverdata/snapserver.conf:/etc/snapserver.conf \
-v /opt/snapcast/serverdata:/serverdata \
--restart unless-stopped \
snapcast-server-0.35.0:local
docker run -d --name snapcast-0.35.0-client1 \
--network snapcast-0.35.0-net \
--restart unless-stopped \
snapcast-client-0.35.0:local \
tcp://server:1704 --soundcard null --latency 0
docker run -d --name snapcast-0.35.0-client2 \
--network snapcast-0.35.0-net \
--restart unless-stopped \
snapcast-client-0.35.0:local \
tcp://server:1704 --soundcard null --latency 0
💡 说明:client 依赖 server 的服务名解析,故三条命令需按序执行且位于同一网络;生产建议仍用 Compose 编排(
depends_on保证顺序、up -d一键重建)。
十、常用运维命令
以下命令均在 /opt/snapcast(compose.yml 所在目录)执行,全部实测:
docker compose ps # 三节点状态与端口映射
docker compose logs -f server # 跟踪服务器日志(Ctrl+C 退出)
docker compose logs --tail 20 client1 # 客户端最近 20 行日志
docker compose restart server # 改配置后重启服务器
docker compose up -d --force-recreate client1 # 重建单个客户端
docker compose down # 停止并移除容器与网络(宿主机数据保留)
docker compose up -d # 重新拉起全栈
docker compose down 实测回显:
Container snapcast-0.35.0-server Removed
Container snapcast-0.35.0-client1 Removed
Container snapcast-0.35.0-client2 Removed
Network snapcast-0.35.0-net Removing
Network snapcast-0.35.0-net Removed
远程控制验证(HTTP JSON-RPC,从宿主机发):
curl -s http://127.0.0.1:8153/jsonrpc -H 'Content-Type: application/json' \
-d '{"id":3,"jsonrpc":"2.0","method":"Server.GetRPCVersion"}'
{"id":3,"jsonrpc":"2.0","result":{"major":23,"minor":0,"patch":0}}
十一、常见问题
Q1:客户端日志报 Failed to create player 或声卡相关错误?
无声卡/虚拟机环境未指定输出设备导致。把 compose 的 client command 保持 --soundcard null(本文实测方式),或用文件输出 --player file --soundcard /path/out.wav;有真实声卡的树莓派则无需该参数(默认 default 设备)。
Q2:服务器日志出现 [Error] (Avahi) Failed to create client: Daemon not running?
容器内没有 avahi 守护进程,mDNS 发布不可用(实测日志原文)。不影响 TCP 直连播放;要消除该报错,在 snapserver.conf 的 [server] 段加 mdns_enabled = false(等价命令行 --server.mdns_enabled=false)。裸机 deb 安装不受影响——systemd 单元自带 Wants=avahi-daemon.service。
Q3:docker compose up 报端口占用?
宿主机 8151/8152/8153 已被占用。ss -lntp | grep -E '8151|8152|8153' 找到占用方,或直接改 compose.yml 端口映射左侧。
Q4:重启后客户端名字/音量丢了?
未挂载 datadir(见第五章实测结论)。按 5.3 增加 ./serverdata/lib:/var/lib/snapserver 挂载。
Q5:流一直 idle,客户端日志反复 No chunks available?
pipe 源没有数据写入。确认宿主机侧生成器/播放器仍在写 serverdata/snapfifo(管道写端断开时 snapserver 会持续等待;写端进程退出需重新拉起)。客户端该实测日志形态:
2026-10-30 00-51-59.287 [Info] (Stream) No chunks available
2026-10-30 00-51-59.287 [Info] (Alsa) Failed to get chunk
Q6:往 /tmp/snapfifo 写数据但服务器没反应?
注意路径一致性:本文 compose 的源 URI 是 pipe:///serverdata/snapfifo(挂载目录内),宿主机写入路径是 serverdata/snapfifo。若用官方默认 pipe:///tmp/snapfifo,则对应容器内 /tmp,宿主机路径不互通——二选一后保证「源 URI、容器内路径、宿主机写入路径」三者一致。
十二、参考链接
- Snapcast 官方仓库:https://github.com/snapcast/snapcast
- v0.35.0 Release(deb 资产来源):https://github.com/snapcast/snapcast/releases/tag/v0.35.0
- 官方安装文档(无 Docker 官方镜像的判断依据):https://raw.githubusercontent.com/snapcast/snapcast/develop/doc/install.md
- 站内相关篇目:《Snapcast 0.35.0 介绍与选型指南》、《Lyrion Music Server 9.1.1 Docker Compose 部署指南》