Skip to content

Airsonic Advanced+Google Drive+Caddy 部署纪实

Published: at 16:35

前言

最近总算是想要摆脱尴尬的听歌处境了。

自从网抑云百万版权倒了之后,下载到本地就变成了唯一的结果。下载的过程也花不了多少时间,下完之后直接就能听,没有任何版权损失的风险。中间试图转成过 QQ,但果然还是被劝退了。

上述列举的都是本地音乐的好处,但如果本地音乐全是好处的话那自然也不会有云音乐的兴起。本地音乐的缺点也很明显,就是多设备同步。

设备一多,事情就开始不对劲了。你开始希望在什么地方都能听到你库存的音乐,但听的前提是你需要把音乐拷贝一份到对应的目标机器上;当你想要分享音乐时,你只能分享一个小至几 M,大至百余兆的音乐文件;以及由于失去了云端的优势,播放记录、播放列表之类的功能也就难以实现与同步。这都是本地播放的劣势。

不知道又没有人说过,解决一切问题的终极手段就是 self-host,音乐也不例外。在有前人 SJ 吃过桃子的情况下[1],我们再摸起来相对就轻松了很多。

目标

为这个平台,我们定下了以下几个目标:

  1. 音乐文件全部存储在 Google Drive 上。
  2. 通过 rclone 挂载目录的形式使 Airsonic 能够读取。
  3. 通过 docker 部署。

目标 1 的出现是因为服务器的硬盘大小不够,不足以支撑将全部文件存下;而目标 2 则是为实现目标 1 而选择的具体方案;至于目标 3,则是为了快速部署而提出的要求。

Google Drive 的实现方案

在目标 2 中,我们指出了计划的实现方案,即通过 rclone 挂载。但 rclone 直接挂载存在两个问题:

  1. 需要守护进程,这一点可以通过 systemd 简单解决。
  2. 迁移过程复杂,这一点有一部分恰好是上一点的解决方案带来的。

并且,由于我们提出了 docker 部署的目标,挂载在外部反而某种意义上使得整个程序过于分散。因此最后我们选择将 Google Drive 挂载为 dockervolume

docker-volume-rclone[2] 就是最终的目标了。我们利用这个 Plugin 运行 rclone mount

安装

安装的话只要通过 docker plugin 就可以完成了:

Terminal window
1
sudo docker plugin install sapk/plugin-rclone

在安装完成后,我们需要配置 rclone,这里直接把你的 rclone.conf 复制过来就可以了。我选择存放在 ~/.config/rclone/rclone.conf

Airsonic Advanced

在准备完音乐源之后,接下来就是本体的搭建了。我们选择的是 Airsonic Advanced[3],这是一个快速迭代的 Airsonic fork,相比原版慢悠悠的开发基调能够更快地发现并解决问题也可以更快地创造问题

作者在 Readme 中给出了 docker 的部署方案,我们只要照着抄一份就行了(

部署

这里我采用了 docker-compose 进行部署,主要是因为需要挂载的 volume 数量有点多了……

1
version: "3.4"
2
3
services:
4
airsonic:
5
image: airsonicadvanced/airsonic-advanced
6
ports:
7
- 127.0.0.1:4040:4040
8
environment:
9
- PUID=0
10
- PGID=0
11
- TZ=Asia/Shanghai
12
- CONTEXT_PATH=
13
- JAVA_OPTS=-Xmx512m
14
volumes:
15
- data:/var/airsonic
16
- playlists:/var/playlists
17
- podcasts:/var/podcast
18
- airsonic-stable:/var/mount/00.stable
19
- airsonic-radio:/var/mount/10.radio
20
healthcheck:
21
test: "ls /var/mount/00.stable && ls /var/mount/10.radio || exit 1"
22
interval: 1m
23
timeout: 15s
24
retries: 3
25
start_period: 15s
26
27
volumes:
28
data:
29
driver: local
30
31
playlists:
32
driver: local
33
34
podcasts:
35
driver: local
36
37
airsonic-stable:
38
driver: sapk/plugin-rclone
39
driver_opts:
40
config: "${RCLONE_CONF_BASE64}"
41
remote: "airsonic-stable:/"
42
args: "--allow-other --dir-cache-time=12h --vfs-read-chunk-size=32M --vfs-read-chunk-size-limit=1G"
43
44
airsonic-radio:
45
driver: sapk/plugin-rclone
46
driver_opts:
47
config: "${RCLONE_CONF_BASE64}"
48
remote: "airsonic-radio:/"
49
args: "--allow-other --dir-cache-time=12h --vfs-read-chunk-size=32M --vfs-read-chunk-size-limit=1G"

environments 中可以看到 PUIDPGID,可以修改成你想要的 UIDGIDCONTEXT_PATH 是为反向代理不在根目录准备的,如在 /music 下,不能以 / 结尾

airsonic 的最后是 healthcheck,这部分主要是为防止 rclone 异常退出而准备的。当挂载目录无法访问,即 rclone 出现故障时,走正常 docker 错误流程就可以了。

最后是 volumes。前三个 local 都没什么问题,最后的两个 airsonic 挂载盘的 args 需要加上 --allow-other 才能让 Airsonic 访问到。而为了使 allow-other 不报错,你还需要修改 /etc/fuse.conf

1
# mount_max = 1000
2
user_allow_other

user_allow_other 的注释去掉,或者如果没有这一行的话,加上即可。

启动

最后就是启动的步骤了。如果你仔细观察了上面的 yaml,你会发现 RCLONE_CONF_BASE64 这个变量。这是我们为了使用 docker-compose 需要准备的。但问题在于我们需要使用 sudo 执行 docker-compose,因此最后我们需要通过 bash -c 执行脚本:

Terminal window
1
sudo bash -c 'export RCLONE_CONF_BASE64="$(base64 /home/yesterday17/.config/rclone/rclone.conf)" && docker-compose up -d'

这里需要注意的是 RCLONE_CONF_BASE64=等号右边,需要用一对引号括住 base64 命令的执行结果,防止由于换行引起的问题。

反向代理

最后的最后就是反代了,这也是让外界能够访问这个服务的关键所在。我简单给一个 Caddy 的配置吧:

1
music.mmf.moe {
2
gzip
3
tls self_signed
4
5
proxy / localhost:4040 {
6
transparent
7
header_upstream X-Forwarded-Proto https
8
header_upstream Connection {>Connection}
9
header_upstream Upgrade {>Upgrade}
10
}
11
12
header / Content-Security-Policy upgrade-insecure-requests
13
}

自己部署记得把上面的 tls self_signed 改成其他正常的 TLS 方案(

配置中的 transparent 是让 Airsonic 使用的,而 X-Forwarded-Proto 则是历史遗留,我也不清楚这样配置能不能让 Airsonic 强制走 https

下面的两行 header_upstream 则是为 WebSocket 准备的,使 Airsonic AdvancedWebSocket 同步能够正常使用。不难发现,这两行和 websocket 预设的效果是一样的[4]。

而最后的 CSP 则是强制 https 的关键,通过 CSP 策略强制浏览器升级不安全的请求。支持 CSP 的浏览器会在读到这个 header 后,会把页面中所有 http 请求都升级到 https

什么?你说浏览器不支持 CSP 怎么办?这样的浏览器还有存在的必要吗(无慈悲)

结语

平台的搭建可以说是费了一番周折,主要可能是在平台选取这一方面耽误了太多的时间。JavaAirsonic 一开始并没有在我的考虑范围之内,因为我觉得我的服务器似乎顶不住它的占用。但经过一番尝试后,最终我还是用回了 Airsonic

Airsonic Advanced 的问题是什么呢?由于它是 Airsonicfork,因此不可能逃出 Airsonic 的局限框架之外。虽然它在 Airsonic 原版的基础上改进了很多,但有一些核心功能的缺失却是没有办法避免的,比如歌词

不过事物的发展是不可能一蹴而就的。在目前的阶段,能有自行车就不错了,毕竟音乐本身才是重点,因此我将眼光更多地放在了音乐内容的整理上。我创建了一个共享盘专门用来让 Airsonic 挂载,并尝试对手头的音乐进行整理。

在我看来,问题最大的是 Artist 的标签。在设计之初他们就没有考虑到多艺术家的复杂之处。艺术家不仅能有多个,还应该有别名。因此计划的第一步就是将手头音乐的艺术家全部都整理成统一的格式:

文档中的说明
文档中的说明

如果你有愿加入音乐的整理,而且我也认识,可以在下面留言或者 TG/TwiPM 我(

嘛,就是这样(

参考

  1. https://blog.seraphjack.top/posts/2020/03/airsonic-setup/
  2. https://github.com/sapk/docker-volume-rclone
  3. https://github.com/airsonic-advanced/airsonic-advanced
  4. https://www.bookstack.cn/read/caddy-cn-doc/src-http.proxy.md#ghf86d