
目标:用 Container Manager 跑起 go-music-dl,网页里搜歌、点下载,文件直接落进
/volume1/Music,Audio Station 立刻能播。全文只需要一个 compose 文件、一次账号初始化、一次路径设置。
一、为什么用容器
go-music-dl 有三种形态:
| 形态 | 平台 | 适合 NAS 吗 |
|---|---|---|
| 桌面客户端 | Windows / macOS | 不适合,是 WebView 壳程序 |
| Web 服务 | 全平台 | 可以,单文件二进制 |
| 容器镜像 | amd64 / arm64 | 推荐,内置 ffmpeg |
镜像里已经打包了 ffmpeg,所以「内嵌封面、写入歌词」这类需要转码的功能开箱可用,不用在 NAS 上另外装。
二、动手前确认三件事
SSH 登录 NAS(控制面板 → 终端机 → 启用 SSH):
uname -m # x86_64 → amd64;aarch64 → arm64
cat /etc/VERSION # DSM 7.2+ 用 Container Manager,7.1/6.x 用 Docker 套件
id 你的账号
id 的输出类似:
uid=1026(你的账号) gid=100(users) groups=100(users),101(administrators)
记下 uid 和 administrators 的组号,等会儿要用。群晖上管理员账号的 uid 通常是 1026,administrators 组固定是 101。
低端 ARM 机型(DS120j、DS220j 等 Marvell 芯片)没有 Docker 支持,只能走二进制 + 计划任务的方式,功能一样但升级要手动。
三、准备目录
两个目录,分开存放:
/volume1/docker/music-dl/data ← 数据库、Cookie、自建歌单(备份只拷这个)
/volume1/Music ← 音乐库,也是 Audio Station 的索引目录
sudo mkdir -p /volume1/docker/music-dl/data
四、docker-compose
Container Manager → 项目 → 新增 → 创建 docker-compose.yml,路径填 /volume1/docker/music-dl,内容:
services:
music-dl:
image: guohuiyuan/go-music-dl:latest
container_name: music-dl
restart: unless-stopped
ports:
- "8088:8080"
user: "1026:101"
entrypoint: ["/bin/sh", "-c"]
command: ["exec ./music-dl web --port 8080 --no-browser"]
volumes:
- /volume1/docker/music-dl/data:/home/appuser/data
- /volume1/Music:/music
- /volume1/Music:/home/appuser/data/downloads
environment:
- TZ=Asia/Shanghai
几个关键点:
user: "1026:101" —— 把 1026 换成你上一步 id 里的 uid,101 是 administrators 组(一般不用改)。镜像默认以 UID 1000 运行,而群晖共享文件夹的权限体系里往往找不到 1000 这个用户,容易写不进去。直接用你的管理员账号身份跑,最省事,生成的文件你在 File Station 里也能直接改。
entrypoint 和 command —— 镜像默认入口会先切到 UID 1000 再启动程序。既然上面已经指定了身份,就必须绕过这一步,否则启动即失败。这两行照抄即可。
三条挂载:
| 宿主机 | 容器内 | 用途 |
|---|---|---|
/volume1/docker/music-dl/data |
/home/appuser/data |
数据库、Cookie、歌单 |
/volume1/Music |
/music |
音乐库,供设置里填 /music |
/volume1/Music |
/home/appuser/data/downloads |
程序的默认下载目录,直连音乐库 |
第三条是省事的关键:程序默认下载目录固定是 data/downloads,把它挂到音乐库上,等于「什么都不填也能下到 /volume1/Music」。
data/downloads 是 data 的子目录,Docker 支持这种嵌套挂载,子挂载覆盖父目录中的同名文件夹,数据库本身不受影响。
如果拉镜像卡住,去 注册表 → 设置 加加速地址,或把 image 改成
docker.m.daocloud.io/guohuiyuan/go-music-dl:latest。
五、启动与初始化
sudo docker logs --tail 20 music-dl
看到这两行就成功:
Web setup token: 一串随机字符
Web started at http://localhost:8080/music
浏览器打开 http://群晖IP:8088/music/setup,填日志里的 token,设置用户名和密码(至少 6 位)。
几点说明:
- 这个账号是应用自己的,跟 DSM 登录账号无关
- token 只在「还没创建管理员」时打印,每次重启都会换新的,旧的立即作废。忘了取就
sudo docker logs music-dl | grep "setup token" - 已经初始化过就不会再有这行,直接访问
/music登录即可 - 忘记密码没有找回命令,只能停容器、移走
data/settings.db重新初始化(会丢 Cookie 和自建歌单,已下载的歌不受影响)
六、下载目录怎么填(最容易错的一步)
登录后右上角齿轮 → 下载 标签 → 下载目录填:
/music
保存。
同一个文件夹的三个叫法
| 你看到的位置 | 路径 |
|---|---|
| File Station / SSH 里 | /volume1/Music |
| 容器内部 | /music |
| 程序默认值 | data/downloads |
设置里要填容器内的路径,也就是 /music。填成 /volume1/Music 会失败,因为那是宿主机路径,容器里看不见(除非挂载点就叫这个名字)。
常见报错:mkdir /Music: permission denied
如果填成大写 /Music,Linux 区分大小写,容器里没有这个目录,程序会试图在根目录创建它——而容器以非 root 身份运行,建不了,于是报这个错。
改成小写 /music 即可。 顺便说明,容器内报出的任何「在根目录建文件夹被拒」都是同一个原因:路径写错了。
提示"当前浏览器无法获取服务器上的完整目录"
在网页版点「选择目录」会弹这句话,不是错误。
那个按钮只在桌面客户端里有效(WebView 会注入选择器)。浏览器只能看到你自己电脑的目录,看不到 NAS 的,所以程序退化成"请手动输入路径"。
直接在输入框填 /music 就行,不要点浏览按钮。右侧工具栏的「打开下载目录」按钮同理,它请求在服务器那台机器上打开文件夹,NAS 没有桌面环境,点了没反应是正常的。
七、验证
# 1. 身份对不对
sudo docker exec music-dl id
# 2. 三条挂载在不在
sudo docker inspect music-dl --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
# 3. 能不能写
sudo docker exec music-dl sh -c "touch /music/.wtest && echo WRITE_OK; rm -f /music/.wtest"
三条都要符合预期,然后网页里搜一首歌点下载:
ls -l /volume1/Music | tail -5
文件出现、属主是你自己的账号、大小不为 0 —— 全链路通了。
最后 Audio Station → 设置 → 共享文件夹 添加 /volume1/Music 并重新索引,DS audio 里就能播放。
八、排错速查
| 现象 | 原因 | 处理 |
|---|---|---|
容器反复重启,日志 SQLite: unable to open database file: out of memory (14) |
容器身份对 data 目录没有写权限(out of memory 是误导性文案,14 是"打不开文件") |
确认 user: 的 uid 正确;仍不行就把 data 换成命名卷,见下 |
启动报 su-exec / operation not permitted |
指定了 user: 但没覆盖 entrypoint |
加上 entrypoint 和 command 两行 |
mkdir /Music: permission denied |
大小写写错 | 改 /music |
mkdir /volume1/...: permission denied |
填了宿主机路径 | 改成容器内路径 |
| 下载失败但目录权限正常 | 平台直链被限流,报错文案误导 | 换音源重试,或去 Cookie 标签填对应平台 |
| 点按钮没反应 | 浏览器缓存了旧页面 | Ctrl+Shift+R 强刷,用无痕窗口验证 |
进 /music/setup 提示 token 失效 |
每次重启都会重新生成 | 从日志取最新的 token |
关于第一条:如果 data 目录所在的共享文件夹启用了 Windows ACL,chown 1000:1000 和 chmod 777 都可能无效(ACL 生效时会忽略 POSIX 模式位)。最省事的绕法是改用命名卷,权限由 Docker 托管:
volumes:
- music-dl-data:/home/appuser/data
volumes:
music-dl-data:
数据会放在 /volume1/@docker/volumes/music-dl-data/_data,备份时从这里拷 settings.db。
九、日常维护
升级
项目 → 操作 → 拉取并重置。或命令行:
cd /volume1/docker/music-dl && sudo docker compose pull && sudo docker compose up -d
备份
只有 settings.db 有价值(账号、Cookie、歌单),音乐文件本身就在 Music 里:
sudo mkdir -p /volume1/docker/music-dl/backup
sudo tar -czf /volume1/docker/music-dl/backup/settings-$(date +%F).tar.gz \
-C /volume1/docker/music-dl data
控制面板 → 任务计划 → 用户自定义脚本,设成每周执行。
外网访问
控制面板 → 登录门户 → 高级 → 反向代理:来源 HTTPS / music.你的域名 / 443,目标 localhost / 8088。不需要 WebSocket。证书用 DSM 自带的 Let's Encrypt。
Cookie
「Cookie」标签按平台填。不填也能搜能下,只是部分平台会限流或降音质;填错反而可能导致解析失败,建议真遇到"无版权 / 需登录"再补。Cookie 有效期有限,过期了需要重新粘。
附:配置速查
访问地址 http://群晖IP:8088/music/ (路径必须带 /music)
数据目录 /volume1/docker/music-dl/data
音乐目录 /volume1/Music (容器内 /music)
端口 8088 → 容器 8080
services:
music-dl:
image: guohuiyuan/go-music-dl:latest
container_name: music-dl
restart: unless-stopped
ports:
- "8088:8080"
user: "1026:101"
entrypoint: ["/bin/sh", "-c"]
command: ["exec ./music-dl web --port 8080 --no-browser"]
volumes:
- /volume1/docker/music-dl/data:/home/appuser/data
- /volume1/Music:/music
- /volume1/Music:/home/appuser/data/downloads
environment:
- TZ=Asia/Shanghai
复制前把
1026换成你id命令里的 uid,101一般是 administrators 组,不用动。
后记
容器部署在群晖上最常见的摩擦点只有一个:容器里以什么身份跑,和你那个文件夹放行了谁,这两件事要对齐。想清楚这一点,后面都是路径写法问题。
同一套思路可以直接搬到 qBittorrent、Navidrome、Immich 这类服务上——先 id 看一眼自己的 uid 和组,再决定 user: 填什么,能省掉大半权限调试时间。
目标:在群晖 NAS 上用 Container Manager 跑起 go-music-dl,下载的歌直接落进
/volume1/Music,Audio Station 立刻能播。这篇不是"复制粘贴就能跑"的速通,而是把过程中踩到的三个坑连同根因一起写清楚。如果你在群晖上跑任何"容器内以非 root 用户写共享文件夹"的服务,这三个坑大概率会全部遇到。
一、这个项目是什么
go-music-dl 是一个聚合搜索 + 解析下载的工具:网页里搜歌,它去网易云、QQ、酷狗、汽水等平台找源,解析出音频直链并下载到本地,可带封面、歌词,还支持 WebDAV 同步和简单的播放器。
它有三种形态:
| 形态 | 平台 | 说明 |
|---|---|---|
| 桌面客户端 | Windows / macOS | Rust + WebView2 写的壳,不适合 NAS |
| Web 服务 | 全平台 | 单文件二进制,music-dl web 起一个网页 |
| 容器镜像 | amd64 / arm64 | 推荐给 NAS,内置 ffmpeg |
群晖上只能走容器(或二进制 + 计划任务),桌面版是 WebView 程序,跑不起来。
二、前置确认
SSH 登录 NAS(控制面板 → 终端机 → 启用 SSH),先确认三件事:
uname -m # x86_64 → amd64;aarch64 → arm64
cat /etc/VERSION # DSM 7.2+ 用 Container Manager;7.1/6.x 用 Docker 套件
id 你的管理员账号 # 记下 uid 和 administrators 的 gid,后面要用
输出长这样:
uid=1026(kang) gid=100(users) groups=100(users),101(administrators),1023(http)
记住两个数字:uid = 1026,administrators 组 = 101。这是后面绕开权限坑的钥匙。
低端 ARM 机型(DS120j、DS220j 这类 Marvell 芯片)没有 Docker 支持,只能走文末的二进制方案。
三、目录规划
只需要两个目录,别把数据库和音乐库塞在一起:
/volume1/docker/music-dl/data ← settings.db、Cookie、自建歌单(备份只拷这个)
/volume1/Music ← 下载的音乐(建议就是 Audio Station 的索引目录)
sudo mkdir -p /volume1/docker/music-dl/data
四、docker-compose 全文
Container Manager → 项目 → 新增 → 创建 docker-compose.yml,路径填 /volume1/docker/music-dl,内容:
services:
music-dl:
image: guohuiyuan/go-music-dl:latest
container_name: music-dl
restart: unless-stopped
ports:
- "8088:8080"
user: "1026:101"
entrypoint: ["/bin/sh", "-c"]
command: ["exec ./music-dl web --port 8080 --no-browser"]
volumes:
- /volume1/docker/music-dl/data:/home/appuser/data
- /volume1/Music:/music
- /volume1/Music:/home/appuser/data/downloads
environment:
- TZ=Asia/Shanghai
user、entrypoint、三条挂载,每一行都不是随手写的,下面逐条解释。
五、坑一:SQLite 报 "out of memory",其实是 ACL 挡住了
现象
容器无限重启,日志反复刷同一段 panic:
panic: Failed to connect to SQLite: unable to open database file: out of memory (14)
Failed to read web auth settings: unable to open database file: out of memory (14)
根因
(14) 是 SQLite 的错误码 SQLITE_CANTOPEN,意思是打不开数据库文件。"out of memory" 是纯 Go 驱动 modernc/glebarez 给的一句误导性错误信息,跟内存毫无关系。
数据库路径是 data/settings.db(相对 WORKDIR /home/appuser),也就是 /home/appuser/data/settings.db,来自挂载的 /volume1/docker/music-dl/data。镜像默认以 UID 1000 运行,于是问题变成:1000 能不能写这个目录。
怎么确认是 ACL
# 1. 用同 UID 的临时容器去写,等价于"容器内那个用户能不能写"
sudo docker run --rm -u 1000:1000 -v /volume1/docker/music-dl/data:/data alpine:3.22 \
sh -c "touch /data/.wtest && echo WRITE_OK || echo WRITE_FAIL"
结果是 WRITE_FAIL。再看权限:
ls -ldn /volume1/docker/music-dl/data
# drwxrwxrwx+ 1 1000 1000 0 Nov 14 12:04 ... ← 注意末尾那个 +
sudo synoacltool -get /volume1/docker/music-dl/data | head -6
# ACL version: 1
# [0] group:administrators:allow:rwxpdDaARWc--:fd--
# [1] user:ContainerManager:allow:rwxpdDaARWc--:fd--
关键就是那个 +:目录启用了 Windows ACL。ACL 里只有 administrators 和 ContainerManager 两条放行记录,没有任何给 UID 1000 的条目。
而在启用了 ACL 的群晖共享文件夹上,POSIX 的拥有者模式位会被忽略——所以你看到 rwxrwxrwx 也没用,chmod 777 不会生效,chown 1000:1000 也只是改了"拥有者"这一栏,并不会在 ACL 里加一条记录。
这就是最容易误判的地方:权限看起来全开,实际写不进去。
解法 A(本文采用):让容器以 ADMIN 身份运行
既然 ACL 放行的是 group:administrators,那就让容器进程带这个组:
user: "1026:101"
1026 = kang 的 uid,101 = administrators 的 gid。这样不用改任何 ACL、不碰任何共享文件夹权限,而且新生成的文件属主就是你自己的账号,SMB 里也能直接管理。
解法 B:数据目录改用 Docker 命名卷
命名卷在 /volume1/@docker/volumes/ 下,权限由 Docker 托管,完全绕开共享文件夹 ACL:
volumes:
- music-dl-data:/home/appuser/data
volumes:
music-dl-data:
代价是备份时要去 /volume1/@docker/volumes/music-dl-data/_data 取文件,稍微绕。
本文选 A,因为下载目录
/volume1/Music本身也是带 ACL 的共享文件夹,用 A 可以一次解决两处写入问题,不用分别处理。
六、坑二:以管理员身份运行,还要覆盖 entrypoint
设了 user: "1026:101" 之后,容器仍然启动失败,报 su-exec 相关的错。
原因是镜像的默认入口会执行 su-exec appuser ... 切到 UID 1000 再启动主程序。你已经用 user: 指定了 1026,进程不是 root,再 su-exec 到 1000 必然失败。
所以要把入口一起覆盖掉:
entrypoint: ["/bin/sh", "-c"]
command: ["exec ./music-dl web --port 8080 --no-browser"]
顺带一个好处:默认入口里还有一句 chown -R 把 data 目录整个递归改属主。绕过入口后这句不再执行,也就不会每次重启都把整个音乐库重新扫一遍改权限——库大了这点很致命。
七、坑三:下载目录有三层路径,填错就 permission denied
这是最容易反复踩的一个。同一个文件夹,在三个地方有三个叫法:
| 位置 | 路径 |
|---|---|
| 群晖宿主机(File Station / SSH) | /volume1/Music |
| 容器内(挂载点) | /music |
| 程序默认值(相对 WORKDIR) | data/downloads |
典型报错一
mkdir /Music: permission denied
填了 /Music——容器内挂载点是小写 /music,Linux 区分大小写,/Music 在容器根目录不存在。容器以 UID 1026 非 root 运行,无权在根目录建文件夹,于是 mkdir 直接 permission denied。
典型报错二
填了 /volume1/Music。这是宿主机路径,容器里看不到它(除非挂载点就叫这个名字),结果同上:尝试在容器根目录建 /volume1/...,失败。
怎么验证
sudo docker exec music-dl ls -ld /music
# drwxrwxrwx ... /music ← 存在,这才是容器内的正确路径
sudo docker exec music-dl ls -ld /volume1/Music
# ls: /volume1/Music: No such file or directory
sudo docker exec music-dl sh -c "touch /music/.wtest && echo WRITE_OK; rm -f /music/.wtest"
# WRITE_OK
本文的双保险
除了 /volume1/Music:/music,还多挂了一条:
- /volume1/Music:/home/appuser/data/downloads
程序默认下载目录就是 data/downloads(源码 core/config_store.go 里 DefaultWebDownloadDir = "data/downloads"),这条挂载等于把默认值直接接到音乐库。也就是说:
- 界面上填
/music→ 落到 Music - 界面完全不填(默认
data/downloads)→ 还是落到 Music
data/downloads 是 data 的子目录,Docker 支持这种嵌套挂载,子挂载覆盖父挂载中的同名目录,数据库目录本身不受影响。
另外要注意:容器内以 1026 运行时,不要填
/volume1/Music,也不要填大写。想保持"看起来像宿主机路径"的话,把挂载写成- /volume1/Music:/volume1/Music,容器内就会出现同名路径。
八、启动与初始化
sudo docker logs --tail 20 music-dl
看到这两行就成功了:
Web setup token: dbf2Zq3eQQAYTSflwvOjCtRm_AyPS2WT
Web started at http://localhost:8080/music
Web setup token只在"还没创建管理员"时打印,每次重启都会换新的,旧的作废- 已经初始化过就不会再有这行,直接登录即可
浏览器打开 http://群晖IP:8088/music/setup,填 token + 用户名 + 密码(≥6 位)。这是应用自己的账号,跟 DSM 的 kang 无关。
忘了密码没有重置命令,只能停容器、移走
data/settings.db重新初始化(会丢 Cookie 和自建歌单,已下载的歌不受影响)。
九、配置下载目录
登录后右上角齿轮 → 下载 标签 → 下载目录填:
/music
保存。
关于"当前浏览器无法获取服务器上的完整目录"
在网页版点"选择目录"会弹出这句提示,这不是错误:
源码里这个按钮只在桌面客户端可用(WebView 会注入 window.musicDlPickDownloadFolder)。浏览器只能看见你自己电脑的目录,看不见 NAS 上的目录,所以程序退化成"让你手填路径"。
正确做法:直接在输入框填 /music,不要点浏览按钮。
同理,右侧工具栏的「打开下载目录」按钮在网页版也没用,它请求的是"在服务器那台机器上打开文件夹",NAS 上没有桌面环境,点了没反应是正常的。
十、验证清单
# 1. 身份对不对
sudo docker exec music-dl id
# uid=1026(kang) gid=101(administrators)
# 2. 三条挂载在不在
sudo docker inspect music-dl --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
# /volume1/docker/music-dl/data -> /home/appuser/data
# /volume1/Music -> /music
# /volume1/Music -> /home/appuser/data/downloads
# 3. 数据库落盘了没
ls -l /volume1/docker/music-dl/data
# settings.db,属主 kang
# 4. 能写不能写
sudo docker exec music-dl sh -c "touch /music/.wtest && echo WRITE_OK; rm -f /music/.wtest"
然后网页里搜一首歌点下载:
ls -l /volume1/Music | tail -5
出现文件、属主是 kang、大小不为 0 —— 全链路通了。
最后去 Audio Station → 设置 → 共享文件夹 把 /volume1/Music 加进索引,DS audio 里就能直接播。
十一、一个容易被当成 bug 的现象:点了按钮没反应
症状:登录后点右上角齿轮,什么也不发生;退出登录后点,倒是会跳登录页。
排查过程走了弯路,最后定位到浏览器缓存了旧页面。
为什么能确定是缓存
从源码看,齿轮按钮的处理函数第一句就是 modal.style.display = "flex",先弹窗再发请求,不存在"等接口返回才显示"。后面每一处 DOM 取值都有空判断,不会静默失败。所以只要函数被调用、且没收到 401,窗口就一定会出现。
能让它"完全没反应"的只剩一种:页面里根本没有 #cookieModal 这个节点 —— 也就是加载到的是旧版 HTML。
验证方法
用无痕窗口打开同一个地址(无痕默认不读缓存、禁用扩展),重新登录后点齿轮,正常。回普通窗口按 Ctrl+Shift+R 强制刷新即可。
顺带两个排查技巧
- 地址后面加
?open_config=1,页面加载完成后会自动调用同一个函数打开设置,绕过按钮点击,能快速区分是"按钮问题"还是"会话问题" - 控制台一行定位:
[typeof openSystemConfig, !!document.getElementById('cookieModal')].join(' | ')
// function | true → 页面正常,问题在点击(或被别的元素挡住)
// function | false → 页面是旧的,强刷
右侧那一列图标间距只有 6px(齿轮 / 定时停止 / 登录退出 / 打开下载目录),手机上很容易点偏到「打开下载目录」,而它在网页版毫无反应,症状和"设置打不开"一模一样。
十二、故障速查表
| 现象 | 根因 | 处理 |
|---|---|---|
SQLite: unable to open database file: out of memory (14) |
ACL 里没有该 UID 的条目,chmod/chown 无效 |
用 user: "uid:gid" 以 administrators 组运行,或改命名卷 |
su-exec / operation not permitted |
覆盖了 user 但没覆盖 entrypoint |
加 entrypoint: ["/bin/sh","-c"] + command: ["exec ./music-dl ..."] |
mkdir /Music: permission denied |
大小写错了,容器内是 /music |
改成小写 |
mkdir /volume1/...: permission denied |
填了宿主机路径 | 改成容器内路径,或把挂载点改成同名 |
下载报 permission denied,但目录权限正常 |
平台解析出的直链被限流,文案误导 | 换音源重试,或去 Cookie 标签填对应平台 |
| 点按钮无反应 | 浏览器缓存了旧页面 / 点偏到相邻图标 | Ctrl+Shift+R,无痕窗口验证 |
进 /music/setup 提示 token 失效 |
每次重启都会换新 token | `docker logs |
| 拉镜像卡住 | 国内网络 | 注册表加加速地址,或镜像名前加 docker.m.daocloud.io/ |
十三、日常维护
升级
Container Manager → 项目 → 操作 → 拉取并重置。或者:
cd /volume1/docker/music-dl && sudo docker compose pull && sudo docker compose up -d
备份
只有 data/settings.db 有价值(账号、Cookie、歌单),音乐文件本身在 Music 里:
sudo mkdir -p /volume1/docker/music-dl/backup
sudo tar -czf /volume1/docker/music-dl/backup/settings-$(date +%F).tar.gz \
-C /volume1/docker/music-dl data
控制面板 → 任务计划 → 用户自定义脚本,设成每周一次。
外网访问
控制面板 → 登录门户 → 高级 → 反向代理:来源 HTTPS / music.你的域名 / 443,目标 localhost / 8088。不需要 WebSocket。证书用 DSM 自带的 Let's Encrypt 即可。
Cookie
「Cookie」标签按平台填。不填也能搜能下,只是部分平台会限流或降音质。填错反而会导致解析失败,建议等真遇到"无版权 / 需登录"再补。
附:最终配置速查
访问地址 http://群晖IP:8088/music/
容器身份 uid=1026(kang) gid=101(administrators)
数据目录 /volume1/docker/music-dl/data (settings.db 在这里)
音乐目录 /volume1/Music (容器内 /music)
默认端口 8088 → 容器 8080
路由前缀 /music(地址必须带这个后缀)
services:
music-dl:
image: guohuiyuan/go-music-dl:latest
container_name: music-dl
restart: unless-stopped
ports:
- "8088:8080"
user: "1026:101"
entrypoint: ["/bin/sh", "-c"]
command: ["exec ./music-dl web --port 8080 --no-browser"]
volumes:
- /volume1/docker/music-dl/data:/home/appuser/data
- /volume1/Music:/music
- /volume1/Music:/home/appuser/data/downloads
environment:
- TZ=Asia/Shanghai
后记
三个坑的共性其实是同一件事:群晖把 Linux 的权限模型又套了一层 ACL,而容器世界默认还是按 UID 思考。所以"容器里以什么身份跑"和"目标目录的 ACL 放行了谁",这两件事必须对齐一次,剩下的都是路径写法问题。
如果以后在群晖上部署别的容器(qBittorrent、Immich、Navidrome 之类),直接照搬 user: "uid:gid" 这个思路,能省掉一大半权限调试时间。