Docker Image for Roon Server

I’m actively maintaining an unofficial Roon Server docker image for Ubuntu. Supports local libraries and cache persists across restarts. Directly connected USB DACs are discoverable and streamable, and native sound output is supported. The container can run unprivileged and without host networking. Healthcheck verifies availability of Roon Display.

The build as of the time of this posting is Roon Server 1.8 build 846 on Ubuntu 20.04.

I also published an Ansible playbook to deploy the image to an Ubuntu server.

The Dockerfile is published to github and open-sourced… so Roon Labs if y’all want to create an official docker image, it’s free for the taking…

https://hub.docker.com/repository/docker/elgeeko/roon-server

12 Likes

Nice setup, especially the networking and user setup.

Do know however the license terms of Roon.

https://roonlabs.com/termsandconditions

There were others before you having a similar setup leading to this comment from Roon official

I made an image too a couple of years ago avoiding this problem.

Happy listening!

Thanks Steef. If Roon Labs asks, I will remove the image from dockerhub.

One way to distribute a docker image without violating the license agreement is to move the curl request to a startup script inside of the docker image. The script will download and extract Roon if it is not present in /opt/RoonServer. /opt/RoonServer could persist across container restarts, and if the end user so chose, any upgrades prompted from within RoonServer would persist. Since this script runs on container creation, RoonServer is never distributed and is not baked into the image.

Alternately, but still similar to above, /opt/RoonServer can simply be mapped into the docker container as a volume, leaving it up to the end user to download and extract RoonServer. This would give all of the benefits of docker while following the exact steps any end user would use to install locally.

Again, happy to discuss with any staff from Roon Labs.

And of course if the image does come off of dockerhub, it should be easy enough for anyone familiar with docker to simply build the dockerfile locally.

Exactly what my image does :slight_smile:

Combining our stuff into an official image would be nice

6 Likes

Hello,
Thks for your work. It’s perfect…
I used a nuc with roon rock, but leaving a machine running just for that was a shame.
I just deployed your docker and it’s perfect for my use!

Thanks again for sharing this !

1 Like

Yay! Thanks for letting me know!

Hey there,

I am currently running roonserver on a windows machine, but plan to build a unraid server soon.
I guess I will be able to use your docker container on unraid OS, right ?

Also, how fast are you updating Roon once a new update comes out ? This is quite important as I am loosing the connection to the metadata identifier each time they decide to update Roon, which currently happens every few days.

Thanks !!!

I haven’t tried this with unraid (nor am I familiar with unraid), but at first glance it appears to support Linux so there’s a good chance it will work.

On first instantiation, the Docker container will download the latest Roon if it has not already been installed in the container. This was to comply with the Roon software license agreement, which does not allow for binary distribution. Upgrading the Roon version is up to the user via the Roon interface.

1 Like

There is already a great docker image on unraid.

steefdebruijn/docker-roonserver

1 Like

I also build an image using PhotonOS instead of Debian, for a lighter and less vulnerable app.

https://hub.docker.com/r/davindisko/roon-photon

I’m running without any problem.

5 Likes

Hi David – I tried your container and it seems to work as well as Steef’s, with a bit less RAM utilisation (1.7-1.8GB vs. 2.3GB at steady-state for my library). Thank you to you both! I hope Roon will release a supported container.

1 Like

Don’t think that will happen. Running RoonServer in a VM is an unsupported environment. So, if you do so, the Tinkering section is where you should post your questions.

Hi, @David_Ferreira.

Do you happen to have a github project for this container? I build my own container based on debian-slim based on the work @Steef_de_Bruijn did but I’d like to see what you’re doing with Photon. Thanks!

Hi, the link I posted is the Github project, where you can find the Dockerfile.

1 Like

That was silly of me. Thanks. I saw the docker hub link and thought the second link was an expansion of the first.

Looking at it, it’s a drop-in replacement for the debian-slim based approach I’ve been using. I’ll give it a shot. Thanks!

1 Like

Thanks again, @David_Ferreira for sharing your Photon-based project and image.

Photon does appear to run a bit leaner than debian slim. Here’s a graph of what I see with debian slim and photon. These are using the same /app, /data, /music directories. What you see is a start of the debian slim followed by a start of photon:

image

The filled portion is memory, the yellowish line is CPU. Photon is using about 300mb less than debian slim. As is typical with Roon, it’s safe to assume that both will grow over time :slight_smile:

This is a view of a grafana dashboard I use created using a combination of grafana, influxdb2, and glances.

I don’t see any obvious downsides to using Photon versus debian slim or alternatives now that you’ve solved the challenge of getting ffmpeg installed given that there is no tdnf package.

Thanks very much for this contribution. It’s good work!

@David_Ferreira Thanks so much for this container. I was able to fork it and build my own just to control how often dependencies are updated or patch anything that breaks. I appreciate your work and being willing to share it. I’m still deciding between Photon and Debian Slim but both seem to work well. Just can’t decide if the simpler dockerfile is worth more memory usage. I like less things that can possibly break. :joy:

1 Like

I ended up cloning the Photon repo and creating my own private one. I utilized Github actions to automate builds of the container so each month the container will rebuild so the latest patches are applied without having to do anything.

To do this you make a folder in the repo called .github then another one inside that called workflows.

Then create a file docker-build.yml.

name: Scheduled Docker Build and Cleanup

on:
  schedule:
    - cron: '0 5 1 * *'  # 12 AM ET on the 1st (5 AM UTC)
  workflow_dispatch:

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set image tag
        id: set-tag
        run: echo "TAG=$(date -u +'%Y-%m-%d-%H-%M')" >> $GITHUB_ENV

      - name: Log current time
        run: date -u

      - name: Log in to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            yourname/docker-roonserver:latest
            yourname/docker-roonserver:${{ env.TAG }}

  cleanup:
    runs-on: ubuntu-latest
    needs: build-and-push

    steps:
      - name: Delete old Docker Hub tags (keep latest 3)
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
          REPO_NAME: yourname/docker-roonserver
          KEEP_COUNT: 3
        run: |
          TOKEN=$(curl -s -H "Content-Type: application/json" \
                -X POST -d '{"username": "'"$DOCKER_USERNAME"'", "password": "'"$DOCKER_PASSWORD"'"}' \
                https://hub.docker.com/v2/users/login/ | jq -r .token)
              
              TAGS=$(curl -s -H "Authorization: JWT $TOKEN" \
                "https://hub.docker.com/v2/repositories/$REPO_NAME/tags?page_size=100" | \
                jq -r '.results | sort_by(.last_updated) | reverse | .[].name')
              
              COUNT=0
              for TAG in $TAGS; do
                if [[ "$TAG" == "latest" ]]; then continue; fi
                COUNT=$((COUNT+1))
                if [ $COUNT -le $KEEP_COUNT ]; then
                  echo "Keeping tag: $TAG"
                  continue
                fi
                echo "Deleting tag: $TAG"
                curl -s -X DELETE \
                  -H "Authorization: JWT $TOKEN" \
                  "https://hub.docker.com/v2/repositories/$REPO_NAME/tags/$TAG/"
              done

With the way this cron is set, on the first of the month at midnight EST a fresh container will be built and only 3 tags will be kept to keep Docker hub clean. You need go to Settings -> Secrets and Variables -> Actions and set a secret called DOCKER_USERNAME to your Docker Hub username and another DOCKER_PASSWORD for a personal access token from docker hub with read, write, and delete permissions in order to be able to delete tags.

Finally we want to create another yml file in that same directory: auto-commit.yml. We need to make a simple commit every now and then to keep the repo active so actions continue to run long term.

name: Auto Commit Ping

on:
  schedule:
    - cron: '0 5 1 * *'  # Every Monday at 00:00 UTC
  workflow_dispatch:     # Optional manual run

jobs:
  auto-commit:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Update timestamp
        run: |
          echo "Last ping: $(date -u)" > .auto-commit.txt

      - name: Commit and push changes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
          git add .auto-commit.txt
          git commit -m "chore: auto-update timestamp" || echo "No changes to commit"
          git push

To make this run you’ll also need to go to Settings -> Actions -> General and give Workflow Permissions, Read and Write Permissions.

That’s all, now you should have your very own self patching container.

Edit: to do this you cannot just fork the repo, scheduled actions will not run. You need to create a fresh repo on Github, install git. Auth with github, git clone the original repo and push up to github.

1 Like

If anyone wants to look at my fork of @David_Ferreira 's Photon container with Github actions to automate patching feel free. I can’t promise reliability as I’m a newb to github actions as well as creating containers. GitHub - mackid1993/docker-roonserver