Running roon on Linux Ubuntu 18.04 as a user (not as root)

When installing the Roon Server on a linux system, it is recommended to run the application as root in order to give access to all the necessary system ressources that roon needs to function properly. Perhaps this is an acceptable work-around on a Rasberry Pi, or other small computers dedicated exclusively to roon. But in general, this is a somewhat unorthodox practice and may create significant security risks, especially if the roon core is running along other services (openvpn, file server, ssh, etc.) on a linux server or desktop.

I am a new roon user, I love the application, and I just installed the Roon Server on a linux computer running as a user other than root. Here is my complete installation procedure in case this could be useful to other people.

The installation was performed on Ubuntu 18.04 LTS Bionic Beaver.

First, check the general manual installation instructions on the roon website:
http://kb.roonlabs.com/LinuxInstall.

Note that many commands must be run as root using the sudo command (preferred approach) or another method.

System preparation before installation

  1. Create a new system user and group named roon with no login access and home directory /var/opt/roon

sudo adduser --system --gecos "Roon Services" --disabled-password --group --home /var/opt/roon roon

Note: According to the Linux Filesystem Hierarchy Standard, a third-party package like roon should be installed in /opt/roon, with variable data in /var/opt/roon (rather than /var/roon).

  1. Create package directory and give user and group ownership to roon (to allow self-updates, among other things)

sudo mkdir -m 755 /opt/roon
sudo chown roon:roon /opt/roon

  1. Use this command to add the roon user to other groups (such as audio). In my case, I needed to add roon to a group named ‘media’ in order to access my music files:

sudo usermod -a -G media roon

Roon Server installation

  1. Download and unpack the roon server package in /opt/roon

sudo -u roon sh -c 'wget -O - "http://download.roonlabs.com/builds/RoonServer_linuxx64.tar.bz2" | tar -xjC /opt/roon -f -'

  1. The server package contains a script to check that all the needed dependencies are met. Run the script with the appropriate user:

sudo -u roon /opt/roon/RoonServer/check.sh

If there is a problem with a dependecy, it needs to be fixed before moving on. For instance, ffmpeg can be installed using the command sudo apt install ffmpeg if the script reports a problem.

  1. At this point, we should have a working Roon Server installation. We can test this by running the start.sh script in the Roon Server directory.

sudo su -s /bin/sh -c '/opt/roon/RoonServer/start.sh' roon

Note: We must use the su -s command to invoke a new shell as user roon with the proper environment variables, and we use sudo to have enough privileges to execute that command.

If everything was configured properly, the process should start and print Initializing, Started, Running … etc. Client applications on other systems should be able to connect to the Roon Core.

The server can be stopped using Ctr-C, the kill command, terminating the shell session, etc.

Starting Roon Server as a service

In order to start Roon Server automatically at boot and run it in the background, we must start Roon Server as a service with systemd.

  1. Create a systemd service unit configuration file named roonserver.service in /etc/systemd/system

sudo nano /etc/systemd/system/roonserver.service

The file must contain the following configurations, comment lines starting with the dial sign can be removed if desired.

[Unit]
Description=RoonServer
After=network-online.target


[Service]
Type=simple
User=roon
Group=roon

# By default, Roon Server creates hidden directories called .RoonServer and
# .RAATServer inside of $HOME. Roon Bridge also uses the .RAATServer directory.
# We can tell Roon Server and Roon Bridge to use a different location for that
# data using these environment variables.
#Environment=ROON_DATAROOT=$HOME
#Environment=ROON_ID_DIR=$HOME

# Even if Roon Server check.sh script reported that the ulimit of open files was
# high enough, systemd ignores the ulimit set for shell sessions. We must tell
# systemd that the roonserver service can raise the limit to 8192.
LimitNOFILE=8192

ExecStart=/opt/roon/RoonServer/start.sh
Restart=on-abort


[Install]
WantedBy=multi-user.target
  1. Enable Roon Server service, this is necessary to enable automatic service restart at boot

sudo systemctl enable roonserver.service

  1. Start service

sudo systemctl start roonserver.service

  1. Check service status to make sure everything is working properly.

sudo systemctl status roonserver.service

Fix for mounting network shares

Roon will try to mount network shares in /mnt, but this is the recommended directory for systems administrators, and only the root user have the permission to write to that directory on Ubuntu 18.04. This was not a problem when Roon Server was running with root privileges, but now our Roon Server (running as user roon) won’t be allowed to create directories to mount networked folders.

There are two main approches for fixing this issue:

a) Mount the network share manually using the mount.cifs command or automatically at boot with /etc/fstab
b) Create a new system group that can write to the /mnt folder and add root and roon user to that group

I have not tested any of these approaches, but here are a few notes. The first approach is the most logical and the most secure, a network share can be mounted in /mnt and we can add that share in roon like a normal local storage folder. However, this will force us to manage network shares ourselves. In the second case, we should be able to mount network shares directly within the roon applications, but this creates the risk that there will be interferences between the shares mounted by the system administrators and Roon Server (in addition to creating security risks).

11 Likes

I use autofs instead of plain mount + /etc/fstab for mounting the network shares. It works seamless in my system. With the plain mount approach, some times I found that the shares were not available, but with autofs always are available, as long as the NAS is alive, of course. It works even in the case where the Roon box boots before the NAS.

1 Like

Thanks for the tutorial cookie_man. I’m not strong on GNU/linux security, but I had been wondering about running Roon Server as a user other than root.

Has anyone had trouble with the ulimit test from check.sh? Mine errors out. I’m running 18.04 LTS. Here’s what I’ve tried:

I edited /etc/security/limits.conf to set a hard nofiles limit for both user roon (and globally too, for testing): roon hard nofile 8192

Since roon has no login privileges, I struggled trying to change ulimit. I settled on sudo su -s /bin/sh $roon. Then I was able to run ulimit -a, which showed nofiles set to 1024. From there, I set ulimit -n 8192. That worked, confirmed by running ulimit -a again.

After exiting out of the shell, though, running check.sh throws the error again. Any hints/tips/suggestions? Thanks in advance.

I am not quite sure what is the issue in your case since we are both using the 18.04 LTS version of Ubuntu, but you must not confuse the hard and the soft limit of open files. The soft limit is the actual limit on the number of open files and this is what matters to roon. The hard limit is how high a user can raise the actual (soft) limit. In other words, I am not sure you needed to change anything in limits.conf and this probably resulted in lowering the hard limit (that should be much higher than 8192).

Assuming that your roon user is roon, can you undo any system-wide changes you made in limits.conf (and other places), reboot, and then run this command:

sudo su -s /bin/sh -c 'ulimit -Hn' roon

This will give you the hard limit of open files, what do you get?

Thanks. I had been thinking that maybe the hard limit for user roon was less than 8192 for whatever reason, but you’re right. Your command returns 1048576. That seems like enough – must be something else.

Yeah, now you can try to raise the soft limit as user roon in a shell session with this command:

sudo su -s /bin/sh -c 'ulimit -n 8192' roon

If you don’t get an error, then try to run the check.sh script with the same command I used in my tutorial above.

1 Like

That worked, somehow – the script no returns [ OK ].

Thanks for your help, much appreciated. I’ll finish the install this week.

My pleasure :slight_smile: and good luck!

Thanks cookie_man! I was planning to do this as well but found this - you saved me some work there, get yourself some milk for dipping.
Well explained as well!

1 Like

Thank you for this guide! So handy - I have hit an issue though, which is that I hit a

Error: Could not create required lock file

In the logs on every restart, and Roon is basically then broken. If i delete the .rn* files from /tmp, i can start successfully again, but it will still fail.

The service is definitely running as roon, and roon is the member of the roon group.

$ groups roon
roon : roon

and the file is owned by roon : roon.

-rw-r--r-- 1 roon roon 0 Nov 14 23:04 /tmp/.rnsems114-

the /tmp folder has the right permissions:

drwxrwxrwt  14 root root     577536 Nov 14 23:07 tmp

So, i am perplexed… I know this isn’t a supported configuration by Roon, but i’d still love to figure out why it’s not working. If anyone has any ideas, let me know!

Thank you!

Hi @Martin_Kemp,

Thanks and sorry to hear you have issues. I am not sure what is the problem in your case. If you are starting the Roon Server with a systemd service at boot, can you disable the service (e.g. sudo systemctl disable roonserver.service), reboot and then start the server directly in a shell (see step 6. above). This can be useful to narrow down the issue. Do you still have an error?

Good luck!

I thought i share my version of a systemd service file for the roon server.
It has some extra security settings. The whole filesystem is mounted read-only for the service, only allowing writes to a specific folder where the the server and all its data is stored which is ‘/zmain/roon’ in my case. I use ‘on-failure’ for the Restart parameter, which is the default and catches a few more cases. ‘Type=simple’ can be omitted, because its the default.

$ systemctl cat roon.service 
# /etc/systemd/system/roon.service
[Unit]
Description=Roon Server
Documentation=https://help.roonlabs.com/portal/en/kb/articles/linux-install
After=network.target

[Service]
User=roon
WorkingDirectory=/zmain/roon
Environment="ROON_DATAROOT=/zmain/roon/roon_data"

ExecStart=/zmain/roon/RoonServer/start.sh

Restart=on-failure
LimitNOFILE=8192

# Security and Sandboxing
NoNewPrivileges=yes
PrivateTmp=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/zmain/roon

[Install]
WantedBy=multi-user.target
1 Like