├── network_diagram.dot └── README.md /network_diagram.dot: -------------------------------------------------------------------------------- 1 | digraph network { 2 | node[shape = box] 3 | edge[dir = none] 4 | 5 | subgraph cluster_home { 6 | label = "Home network\n192.168.1.0/24" 7 | bgcolor="lightgreen" 8 | 9 | subgraph cluster_client { 10 | label = "Linux\nVPN client" 11 | bgcolor="lightgrey" 12 | br0[label = "br0\nvirtual bridge\n192.168.1.x (obtained via DHCP)", shape = ellipse, style = filled, fillcolor="white"] 13 | c_eth[label = "ens33\nethernet\ninterface", shape = ellipse, style = filled, fillcolor="white"] 14 | c_tap0[label = "tap0\nvirtual\ninterface", shape = ellipse, style = filled, fillcolor="white"] 15 | 16 | 17 | br0 -> c_eth 18 | br0 -> c_tap0 19 | } 20 | 21 | { 22 | router[label = "DSL\nrouter", style = filled, fillcolor="lightgrey"] 23 | rank = min 24 | } 25 | 26 | roon_endpoint[label = "Roon\nendpoint", style = filled, fillcolor="lightgrey"] 27 | root_remote[label = "Roon\nremote", style = filled, fillcolor="lightgrey"] 28 | 29 | c_eth -> router 30 | roon_endpoint -> router 31 | root_remote -> router 32 | } 33 | 34 | subgraph cluster_server { 35 | label = "Linux cloud\nRoon server" 36 | bgcolor="lightgrey" 37 | s_eth[label = "ethernet interface\n1.2.3.4 (public static IP)", shape = ellipse, style = filled, fillcolor="white"] 38 | s_tap0[label = "tap0\nvirtual interface\n192.168.1.123 (private static IP)", shape = ellipse, style = filled, fillcolor="white"] 39 | } 40 | 41 | roon_arc[label = "Roon ARC", style = filled, fillcolor="lightgrey"] 42 | 43 | c_tap0 -> s_tap0[label = "Layer 2 connection\nover VPN", color = green, fontcolor = green] 44 | br0 -> s_eth[label = "OpenVPN\nUDP-1194", dir = forward, color = blue, fontcolor = blue] 45 | root_remote -> s_tap0[label = "Server control\nover VPN", dir = forward, color = red, fontcolor = red] 46 | s_tap0 -> roon_endpoint[label = "Audio stream\nover VPN", dir = forward, color = red, fontcolor = red] 47 | roon_arc -> s_eth[label = "Server control\n\over internet\nTCP-55000", dir = forward, color = blue, fontcolor = blue] 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Setting up Roon on a Linux cloud server 2 | 3 | ## 🚀 Introduction 4 | 5 | This guide will walk you through the process of setting up a Linux cloud server running [Roon](https://roonlabs.com/), connected to your home network via an [OpenVPN](https://openvpn.net/community/) Layer 2 VPN. This setup allows Roon to be virtually part of your home network while running in the cloud. 6 | 7 | ### 💡 Benefits of a cloud solution over an [Intel NUC](https://www.intel.com/content/www/us/en/products/details/nuc.html) 8 | 9 | - Cost efficiency: Opting for a cloud-based Roon Core is more cost-effective than purchasing the necessary hardware in the short to medium term. For instance, as of April 2023, I personally spend about 7 euros per month on this cloud infrastructure. 10 | - Uninterrupted access: Enjoy continuous access to [Roon ARC](https://roonlabs.com/arc) thanks to the elimination of power cuts, internet connection disruptions, and home DSL router issues. 11 | - Enhanced data protection: The absence of power cuts in a cloud-based solution reduces the risk of corruption for your locally stored FLAC files, ensuring your music collection remains safe. 12 | - Effortless scalability: When you need more storage or processing power, simply purchase additional cloud storage or CPUs to meet your demands. If you find cheaper storage offered by a third-party cloud provider, you can also attach it to your existing cloud server and seamlessly utilize it, although this option is not currently covered in this guide. 13 | - Reduced energy consumption: Integrating the OpenVPN client into an existing home device or appliance eliminates the need for extra energy usage. In the worst-case scenario, using a dedicated Raspberry Pi will keep energy consumption minimal, at less than 5 watts. 14 | - No fan noise: Since you are running your Roon Core on a cloud server, there is no fan noise generated. This allows you to avoid having to hide your Roon Core far from your speakers or invest in a fanless system. 15 | 16 | ### 🤝 Motivation and collaboration 17 | 18 | Numerous Roon users are in search of a practical and streamlined method to operate Roon on a cloud machine. While there have been successful endeavors, piecing together a complete guide and an easily reproducible solution from fragmented forum discussions can be quite a challenge. 19 | 20 | To address this, I invite you to engage in forum discussions about the proposed solution and contribute back to this guide after these conversations. To do so, please follow the standard [GitHub workflow](https://docs.github.com/en/get-started/quickstart/contributing-to-projects): fork the repository, make your changes, commit, and submit a pull request. 21 | 22 | ### 🛠️ System configuration 23 | 24 | I opted for [Linux Ubuntu Server 22.04.2 LTS](https://ubuntu.com/download/server), a widely used Linux distribution, for both the cloud server and the home VPN endpoint (the VPN client). However, these instructions can be easily adjusted to accommodate other Linux distributions. 25 | 26 | #### ☁️ Cloud server 27 | 28 | I chose an affordable solution that delivers adequate performance for my requirements, and it's possible that an even less powerful CPU option would suffice, as detailed in the performance section below. The specifications of the selected solution are as follows: 29 | - Hypervisor platform: OpenStack 30 | - Processors: 2 AMD vCPUs 31 | - RAM: 4 GB 32 | - Storage: 40 GB SDS (Software-Defined Storage) NVMe 33 | 34 | #### 🏠 Home client 35 | 36 | To accommodate a broader range of users, the instructions provided below are based on a generic Ubuntu Server 22.04.2 LTS. However, for my personal setup, I utilize a [Raspberry Pi 4](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) with [specific Linux Ubuntu 22.04.2 LTS version](https://ubuntu.com/download/raspberry-pi). Please note that the Raspberry Pi version of Ubuntu has some minor differences compared to the standard version, such as a slightly different network configuration file naming. 37 | 38 | If you have an existing home device that can run OpenVPN, you are encouraged to experiment with it as an alternative. Some examples include: 39 | 40 | - Linux Ubuntu 22.04.2 LTS on a Raspberry Pi (my personal setup) 41 | - Any appliance running on a Raspberry Pi, such as [Home Assistant](https://www.home-assistant.io/), [Pi-hole](https://pi-hole.net/) or [RetroPie](https://retropie.org.uk/) 42 | - QNAP or Synology NAS 43 | - Windows PC or Mac 44 | 45 | 💡 Side note: As Home Assistant has been mentioned, it's worth highlighting that you can utilize its [automation features](https://www.home-assistant.io/integrations/roon/) to manage various aspects of Roon playback, like volume control, playlist selection, and more, depending on specific events or triggers. Want to start Roon playback when your Alexa alarm goes off in the morning or when you return home in the evening? It's entirely possible! 😎 46 | 47 | ### 📊 System performance 48 | 49 | The performance of this setup is excellent, with no audio problems or interruptions. Based on the CPU usage data below, it is likely that even a lower-end cloud server would suffice. It is worth noting that I am not using any Roon DSP, only volume leveling. The following data was collected from the cloud server while playing a track from Qobuz, FLAC 192 kHz, 24 bit (I purposefully selected the most demanding audio format available): 50 | 51 | - Playing to a Platin Hub connected to Buchardt A500 52 | - Average CPU usage: 20% 53 | - RAM usage: 2.5 GB 54 | - Home bandwidth usage: 10 Mbps 55 | - Playing to a Chromecast Audio 56 | - Average CPU usage: 6% 57 | - RAM usage: 2.5 GB 58 | - Home bandwidth usage: 3.4 Mbps 59 | 60 | As demonstrated by the data, any modern fiber or DSL home internet connection can handle these constant bandwidths, resulting in a seamless audio experience. 61 | 62 | ## 🌐 Network Diagram Overview 63 | 64 | For the sake of example, we'll be using the following information in this guide: 65 | - Public IP address of the cloud server: 1.2.3.4 66 | - Home network IP class: 192.168.1.0/24 67 | - Home network IP address assigned to the Roon server: 192.168.1.123 (it should be a static IP address, out of the DHCP assignment range) 68 | - Ethernet interface name of the Linux client: ens33 69 | 70 | Please consider these as examples and adjust them accordingly to match your home network and cloud server setup. 71 | 72 | The following network diagram illustrates the connections between the various components involved. Don't be intimidated by the complexity of the diagram; although it may appear complicated, the setup process itself is quite straightforward and easy to follow. 73 | - Black lines: Physical connections 74 | - Green line: Virtual Layer 2 link (VPN) 75 | - Blue lines: IP connections over the internet 76 | - Red lines: IP connections over VPN 77 | 78 | ![Network diagram](https://user-images.githubusercontent.com/471234/232319930-fb11f2d5-a2fa-4921-8a91-1c9823d942f9.svg) 79 | 80 | ## ☁️🔧 Cloud server setup 81 | 82 | Obtain root permissions to execute subsequent commands without using "sudo" prefix: 83 | ``` 84 | sudo su 85 | ``` 86 | 87 | Install the necessary packages: 88 | ``` 89 | apt install openvpn easy-rsa ffmpeg cifs-utils lbzip2 90 | ``` 91 | 92 | Determine the name of the internet-facing interface by identifying the one that displays the public cloud IP address: 93 | ``` 94 | ip addr 95 | ``` 96 | 97 | Assuming the internet-facing interface is "ens3", open the required port for OpenVPN: 98 | ``` 99 | ufw allow in on ens3 proto udp to any port 1194 100 | ``` 101 | 102 | Allow all traffic from your home network, as tap0 is the virtual interface that leads to your home network and will subsequently be used by OpenVPN: 103 | ``` 104 | ufw allow in on tap0 105 | ``` 106 | 107 | Open the Roon ARC port on the internet-facing interface: 108 | ``` 109 | ufw allow in on ens3 proto tcp to any port 55000 110 | ``` 111 | 112 | Check the firewall status: 113 | ``` 114 | ufw status 115 | ``` 116 | 117 | Enable the firewall if it is not already enabled: 118 | ``` 119 | ufw enable 120 | ``` 121 | 122 | Generate the necessary OpenVPN cryptographic initialization data and client/server certificates: 123 | ``` 124 | make-cadir /root/cadir 125 | cd /root/cadir 126 | ./easyrsa init-pki 127 | ./easyrsa build-ca nopass 128 | ./easyrsa build-server-full server nopass 129 | ./easyrsa build-client-full client nopass 130 | ./easyrsa gen-dh 131 | openvpn --genkey secret ta.key 132 | ``` 133 | 134 | Copy the server-side certificate to the appropriate directory (client-side certificates will be copied later): 135 | ``` 136 | cp -av pki/ca.crt /etc/openvpn 137 | cp -av pki/dh.pem /etc/openvpn 138 | cp -av ta.key /etc/openvpn 139 | cp -av pki/issued/server.crt /etc/openvpn 140 | cp -av pki/private/server.key /etc/openvpn 141 | ``` 142 | 143 | Create an OpenVPN configuration file: 144 | ``` 145 | cd /etc/openvpn 146 | nano server.conf 147 | ``` 148 | 149 | Paste the following into the file you are editing, adjusting the IP address and subnet mask to fit your home network. Ensure the chosen address is outside your DHCP assignment range to prevent conflicts. Save the file using CTRL-X: 150 | ``` 151 | dev tap0 152 | proto udp4 153 | ifconfig 192.168.1.123 255.255.255.0 154 | tls-server 155 | dh dh.pem 156 | ca ca.crt 157 | cert server.crt 158 | key server.key 159 | tls-auth ta.key 0 160 | cipher CHACHA20-POLY1305 161 | persist-key 162 | persist-tun 163 | keepalive 10 120 164 | verb 1 165 | ``` 166 | 167 | Verify the OpenVPN configuration file and ensure all required files are accessible by running OpenVPN in the foreground with increased verbosity. If no errors appear, exit with CTRL-C: 168 | ``` 169 | openvpn --config server.conf --verb 3 170 | ``` 171 | 172 | Start OpenVPN in the background: 173 | ``` 174 | systemctl start openvpn@server.service 175 | ``` 176 | 177 | Confirm OpenVPN has started: 178 | ``` 179 | systemctl status openvpn@server.service 180 | ``` 181 | 182 | Enable automatic OpenVPN startup during system boot: 183 | ``` 184 | systemctl enable openvpn@server.service 185 | ``` 186 | 187 | Download Roon: 188 | ``` 189 | cd /root 190 | curl -O https://download.roonlabs.net/builds/roonserver-installer-linuxx64.sh 191 | ``` 192 | 193 | Grant execution permissions to the script: 194 | ``` 195 | chmod +x roonserver-installer-linuxx64.sh 196 | ``` 197 | 198 | Run the installation script: 199 | ``` 200 | ./roonserver-installer-linuxx64.sh 201 | ``` 202 | 203 | Remove the script as it is no longer needed: 204 | ``` 205 | rm roonserver-installer-linuxx64.sh 206 | ``` 207 | 208 | Reboot the server to verify all services start automatically: 209 | ``` 210 | reboot 211 | ``` 212 | 213 | Upon completing these steps, your cloud server should be successfully set up with OpenVPN and Roon. 214 | 215 | ## 🏠🔧 Home client setup 216 | 217 | Obtain root permissions to execute subsequent commands without using "sudo" prefix: 218 | ``` 219 | sudo su 220 | ``` 221 | 222 | Install the necessary packages: 223 | ``` 224 | apt install openvpn bridge-utils 225 | ``` 226 | 227 | Edit the network configuration: 228 | ``` 229 | nano /etc/netplan/00-installer-config.yaml 230 | ``` 231 | 232 | Assuming ens33 is the name of your ethernet interface, modify the configuration file as follows, to setup the layer 2 bridge that will be later used by OpenVPN. Save the file using CTRL-X: 233 | ``` 234 | network: 235 | ethernets: 236 | ens33: 237 | dhcp4: false 238 | version: 2 239 | bridges: 240 | br0: 241 | interfaces: [ens33] 242 | dhcp4: yes 243 | ``` 244 | 245 | Apply the new network settings: 246 | ``` 247 | netplan apply 248 | ``` 249 | 250 | Verify the updated network configuration by checking internet connectivity. Exit using CTRL-C: 251 | ``` 252 | ping www.google.com 253 | ``` 254 | 255 | Transfer the required client files from the server using rsync. Alternatively, you can use tools like Filezilla, but ensure file permissions are preserved. Keep in mind that rsync will prompt you for your cloud server root password so that it can access and fetch the files. Also, remember to replace 1.2.3.4 with your cloud server's public IP address: 256 | ``` 257 | rsync -av root@1.2.3.4:/root/cadir/pki/ca.crt /etc/openvpn 258 | rsync -av root@1.2.3.4:/root/cadir/ta.key /etc/openvpn 259 | rsync -av root@1.2.3.4:/root/cadir/pki/issued/client.crt /etc/openvpn 260 | rsync -av root@1.2.3.4:/root/cadir/pki/private/client.key /etc/openvpn 261 | ``` 262 | 263 | Create an OpenVPN configuration file and open it with a text editor: 264 | ``` 265 | cd /etc/openvpn 266 | nano client.conf 267 | ``` 268 | 269 | Copy the following content into the file. Replace 1.2.3.4 with your cloud server's public IP address. Save the file using CTRL-X: 270 | ``` 271 | dev tap0 272 | proto udp4 273 | tls-client 274 | remote 1.2.3.4 275 | resolv-retry infinite 276 | nobind 277 | ca ca.crt 278 | cert client.crt 279 | key client.key 280 | tls-auth ta.key 1 281 | remote-cert-tls server 282 | cipher CHACHA20-POLY1305 283 | persist-key 284 | persist-tun 285 | keepalive 10 60 286 | verb 1 287 | script-security 2 288 | up /etc/openvpn/bridge_setup 289 | ``` 290 | 291 | Create a helper script to set up the bridge automatically once the VPN connection is established: 292 | ``` 293 | nano bridge_setup 294 | ``` 295 | 296 | 297 | Copy the following content into the file, save and exit with CTRL-X: 298 | ``` 299 | #!/bin/bash 300 | 301 | ip link set tap0 up 302 | brctl addif br0 tap0 303 | ``` 304 | 305 | Grant execute permissions to the helper script: 306 | ``` 307 | chmod +x bridge_setup 308 | ``` 309 | 310 | Test the OpenVPN configuration and certificate file access by running OpenVPN in the foreground with increased verbosity. If no errors are encountered, exit with CTRL-C: 311 | ``` 312 | openvpn --config client.conf --verb 3 313 | ``` 314 | 315 | Launch OpenVPN in the background: 316 | ``` 317 | systemctl start openvpn@client.service 318 | ``` 319 | 320 | Confirm OpenVPN has started successfully: 321 | ``` 322 | systemctl status openvpn@client.service 323 | ``` 324 | 325 | Enable OpenVPN to start automatically upon system boot: 326 | ``` 327 | systemctl enable openvpn@client.service 328 | ``` 329 | 330 | Reboot the client to ensure all services start automatically: 331 | ``` 332 | reboot 333 | ``` 334 | 335 | Upon completing these steps, your home client should automatically establish a VPN connection to the cloud server and bridge it to your home network. 336 | 337 | ## 🔍 Troubleshooting 338 | 339 | ### Connecting Roon remote to Roon server 340 | 341 | Sometimes, when setting up a Roon remote for the first time, it may not automatically find the Roon server on your local network. If this occurs, follow these steps: 342 | 343 | - Click on the "Help" link in the Roon remote app: 344 | 345 | ![Roon remote troubleshoot step 1](https://user-images.githubusercontent.com/471234/232323760-8ee042f5-1772-40a3-a186-06282095538f.jpg) 346 | 347 | - Enter the Roon server's home network IP address (e.g. 192.168.1.123): 348 | 349 | ![Roon remote troubleshoot step 2](https://user-images.githubusercontent.com/471234/232323770-e80b476e-6610-489e-83b5-d4c0e7588b33.jpg) 350 | 351 | ### Resolving OpenVPN connection issues 352 | 353 | If you encounter OpenVPN connection issues, often due to missing or inaccessible configuration files or incorrect file permissions, follow these steps: 354 | - Open a terminal on both the server and client consoles. 355 | - On the server terminal, get root permissions, stop the OpenVPN service and ensure no OpenVPN instances are running (the second command should return no output): 356 | ``` 357 | sudo su 358 | systemctl stop openvpn@server.service 359 | ss -anp|grep openvpn 360 | ``` 361 | - On the client terminal, get root permissions, stop the OpenVPN service and ensure no OpenVPN instances are running (the second command should return no output): 362 | ``` 363 | sudo su 364 | systemctl stop openvpn@client.service 365 | ss -anp|grep openvpn 366 | ``` 367 | - Run OpenVPN in the foreground on the server terminal with increased verbosity. You may later exit using CTRL-C: 368 | ``` 369 | cd /etc/openvpn 370 | openvpn --config server.conf --verb 3 371 | ``` 372 | - Run OpenVPN in the foreground on the client terminal with increased verbosity. You may later exit using CTRL-C: 373 | ``` 374 | cd /etc/openvpn 375 | openvpn --config client.conf --verb 3 376 | ``` 377 | If everything is set up correctly, you should see log messages on both terminals indicating that the connection has been established. If not, review the error messages and work to resolve them. 378 | 379 | Once you've identified and fixed any issues: 380 | - Restart the background OpenVPN instance on the server: 381 | ``` 382 | systemctl start openvpn@server.service 383 | ``` 384 | - Restart the background OpenVPN instance on the client: 385 | ``` 386 | systemctl start openvpn@client.service 387 | ``` 388 | --------------------------------------------------------------------------------