I have amassed a large collection of CDs and ripped all of them to FLAC, and recently started using Tidal to listen to expand my lossless music collection further. Sonos made it easy to stream my local files throughout the house, but the Sonos apps only let you browse the local and Tidal collections independently. Sonos also lacks support for my high-res audio and can’t take advantage of the good DACs I use on my PCs. Roon helps address both of those, combining local & Tidal collections into a single database and streaming it to any device. However, it needs a central server to hold all that metadata and provide a consistent experience across all devices. I’m tired of maintaining separate VMs for each server app, so it sounds like a job for Docker!
Parts needed
- AirSonos - this is an AirPlay to Sonos bridge. It will make all of your Sonos devices show up on the network as if they were native AirPlay devices. There are some step by step instructions on how to make this work on the Roon community forum
- Roon Server
Setting up AirSonos
sudo docker run -d --restart=always --net="host" --name="airsonos" \
-p 5000-5050:5000-5050/tcp justintime/airsonos
Right away, it found all 3 of my Sonos devices:
patrick@coldbrew:~$ docker logs 90
*** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
No SSH host key available. Generating one...
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Creating SSH2 ECDSA key; this may take some time ...
*** Running /etc/my_init.d/10_dbus.sh...
*** Running /etc/rc.local...
*** Booting runit daemon...
*** Runit started as PID 79
ok: run: avahi: (pid 88) 0s
ok: run: dbus: (pid 87) 0s
Searching for Sonos devices on network...
Living Room (@ 192.168.1.241:1400, RINCON_B8E937A863E801400:46)
Studio (@ 192.168.1.111:1400, RINCON_B8E937A863E801400:49)
Master Bedroom (@ 192.168.1.107:1400, RINCON_000E583F00AC01400:132)
Search complete. Set up 3 device tunnels.
Once I figured out how to use AirPlay in iOS 10, it worked. My mistake was that the AirPlay button is now for display only. Once something is playing on the phone, swipe up from the bottom then left.
There’s a bit of delay, but hey, it works.
Setting up Roon Server
- mikedickey/roonserver - Dockerfile on GitHub
- ronch/roon-server - No link to Dockerfile
I decided to build mikedickey’s image myself, rather than pulling it to make sure I had the latest version.
git clone https://github.com/mikedickey/RoonServer
cd RoonServer
docker build -t roonserver .
His instructions said to run docker run --name RoonServer --net=host -d -v /home/roon:/var/roon -v /home/music:/music mikedickey/roonserver
, but had a few concerns about it:
- I don’t have my music on the same server as the container, and I want to mount it read-only. I use J.River Media Center for all tagging instead, and don’t want any other apps modifying or retagging files.
- It seems unreasonable to map a whole home directory from the server.
Instead, I want to use a Docker volume to store /var/roon, and map in my existing file server read only.
I created a new user ‘roon’, and gave it read only permissions to my file share.
On the Linux container host, I followed the steps for MountWindowsSharesPermanently to mount my music to /mnt/musicarchive. The user I created on the Windows side only has read only access to the share.
Creating a container volume is easy, just put a unique name after -v for the server side of the path such as -v roondata:/var/roon
.
This changed my command line to
docker run --name RoonServer --net=host -d -v roondata:/var/roon -v /mnt/musicarchive:/music roonserver
Setting up Roon on Windows
I’m not going to use my laptop as a server, but I would like to use it for control and output. I downloaded and installed the Windows 64 bit version from the download site
One of the first steps was , which showed the right IP for my Linux server running the container. I chose it, then logged in using my Roon login and password.
It had my Tidal collection there immediately, but didn’t have my local collection.
Adding the local collection
I clicked the hamburger menu, went to Settings, Storage, Watched Folders then clicked “Add Folder”. There’s a local folder button, so I clicked it and entered /music/
.
CPU usage peaked on the server for a bit - docker stats
showed that the Roon server container was busy indeed:
none
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a55f30b3fbab 25.23% 800.1 MiB / 1.945 GiB 40.17% 0 B / 0 B 1.36 MB / 12.89 MB 77
90a23eba41d4 7.76% 94.77 MiB / 1.945 GiB 4.76% 0 B / 0 B 24.57 MB / 1.321 GB 20
f7a429a746a9 0.15% 88.54 MiB / 1.945 GiB 4.45% 136.8 kB / 14.9 kB 66.54 MB / 307.4 MB 26
f3c0464a67f2 0.01% 40.09 MiB / 1.945 GiB 2.01% 156.2 kB / 64.95 kB 41.07 MB / 106.5 kB 10
e63e9267361c 0.13% 56.1 MiB / 1.945 GiB 2.82% 2.309 MB / 4.979 MB 24.87 MB / 280.3 MB 30
3c6d0cd0e929 0.01% 110.4 MiB / 1.945 GiB 5.54% 14.11 MB / 11.57 MB 66.84 MB / 20.55 MB 11
867b129d08e4 0.11% 19.09 MiB / 1.945 GiB 0.96% 149.2 kB / 27.91 kB 16.27 MB / 5.39 MB 26
1d3f3f46c3ce 0.01% 22.06 MiB / 1.945 GiB 1.11% 191.1 kB / 211.3 kB 12.75 MB / 49.15 kB 11
Adding audio devices
Next, I needed to configure audio devices for Roon. Roon is designed to give one consistent view of the music collection, but stream it anywhere. I started off with my laptop’s local “Realtek High Definition Audio” under “Connected to this PC”, which isn’t anything out of the ordinary. I scrolled down further to “Networked” - and the Sonos devices (via AirSonos) were already listed. I clicked “Enable” next to one of them, entered a name, and it was good to go.
Notice - instead of showing the URL of my physical network (192.168.1.x), it actually showed the AirSonos container’s IP in the 172.x.x.x subnet.
And that’s it!
Roon Core is up and running in a container, and will automatically restart if stops unexpectedly or if the Docker Engine restarts. Because it’s using host
networking, you can only run one instance per server. That’s not too much of a problem though since that would also need 2 Roon accounts.
Time to update
When a new update is available, you can simply build a new container and launch a new instance using the same data volume as before.
docker stop roonserver
docker rm a55 # the previous running container ID
docker build --no-cache -t roonserver .
docker run --name RoonServer --net=host -d -v roondata:/var/roon -v /mnt/musicarchive:/music roonserver
Once it’s up and running, you can see that your databases and history are preserved:
Things to think about for later
I could probably run all of this in Windows containers and skip the Linux VM altogether. Given that others had tried it on Linux and succeeded, I thought I would start there first. I am concerned about being able to keep audio streaming under load which could be difficult when the fileserver VM is doing a backup. If I get those into a single VM (with Roon in a container), the IO & memory scheduling should work better.
Deploy with Docker-Compose - Move Roon Server’s configuration file out of the container into a container volume - Build directly from Docker-Compose to make sure it’s always up to date