RoonBroadcastRelay - Make Roon work on complex network infrastructures (VPN/VLAN)

Hi everyone,

After struggling to get Roon working reliably across VPNs and VLANs, I built a dedicated solution. Existing tools like udp-proxy-2020 helped with basic scenarios, but fell short with WireGuard roadwarrior clients, site-to-site tunnels, multiple VLANs, or combinations of these.

Roon uses UDP broadcast/multicast for discovery, which doesn’t cross network boundaries. But there’s a deeper issue: Roon endpoints register using their source IP. If that IP gets rewritten by a relay or NAT, the server can’t connect back to the client. This is why your phone might find the Roon server but never appear as an audio output.

What RoonRelay does

  • Forwards Roon discovery packets across VPNs, VLANs, and remote sites
  • Preserves original source IP using raw sockets
  • Supports site-to-site deployments with a tunnel between relay instances

Lightweight C# (.NET 8) service, runs on Linux as a systemd service.

Please read before asking questions - most setups are covered:

  • README - Overview and quick start
  • EXAMPLES - Detailed scenarios with network diagrams, firewall rules, WireGuard/OPNsense config

Contributions

The current documentation covers WireGuard and OPNsense. Contributions are appreciated to expand coverage:

  • Other VPN solutions (OpenVPN, IPsec, Tailscale, …)
  • Other firewalls (pfSense, Ubiquiti, MikroTik, …)
  • Docker deployment
  • General improvements and corrections

GitHub: GitHub - simonefil/RoonBroadcastRelay

4 Likes

This is a solid solution. Preserving the original source IP via raw sockets is the correct way to solve the “split-brain” behavior where Roon can discover the Core but cannot stream audio.

There are, however, a few architectural constraints worth documenting to avoid user confusion:

  • uRPF (Reverse Path Forwarding): Because the relay injects packets with a preserved (spoofed) source IP, routers with Strict uRPF enabled (common on enterprise and UniFi gear) will drop this traffic. Users may need to disable strict uRPF or switch to loose mode on relay/VPN interfaces.
  • Alpine vs. Debian: Be cautious when using Alpine Linux (musl libc) for Docker images. Raw socket handling in .NET (IP_HDRINCL) has historically shown checksum inconsistencies on musl. Debian/Ubuntu-based images are a safer default.
  • Windows compatibility: Although this is a .NET project, modern Windows networking stacks prevent UDP source-IP spoofing via raw sockets. It is best to explicitly document this as a Linux-only solution.
  • MTU overhead: Encapsulating traffic inside WireGuard reduces MTU. Discovery packets are small, but fragmentation issues could arise with larger responses or metadata.

Overall, great work addressing the root cause rather than just proxying multicast traffic.

2 Likes

Thank you very much for your support and for the excellent points you raised. I will add a FAQ section to the README to include what you highlighted regarding uRPF and Windows incompatibilities. As for the Docker setup, I hope that some kind soul will be able to test it and provide a working docker-compose file so it can be added to the documentation. I cannot provide since I use normal LXC containers in my setup.

Given that there is a Roon Ready Relay product/feature, maybe a different name would be nice Introducing the next evolution of Roon Ready tech!

1 Like
  • Software and repository renamed
  • Corrected examples after testing with iOS devices
  • Added binary for arm (aarch64)
1 Like
  • Added binaries for MacOS (not tested)
  • Added support for other protocols other than RAAT but still used by Roon: AirPlay, SSDP (Chromecast, Sonos, LINN), Squeezebox. Not completely test, feedbacks are very welcomed

Where can I find the Mac binary?

I gotta say RoonBroadcastRelay is the first time I got remote streaming of Roon to work well. Besides Arc.

Finally a solution on my Mac :slight_smile:

All the binaries are in the releases section of the repo. Binaries for MacOS are not tested. Only binaries for linux are tested and confirmed working.

Oh. So what does the Mac binary do exactly?

I don’t really understand the question. It does the same as the linux binary. It’s just compiled for a different OS.

So it’s a Mac app that does the port forwarding/mapping or such

Sure. Check the examples in the repo for configuration.

Hi, just want to let you know that I’ve just setup your solution on my home network; I already had VPN access, and this covers the extra mile: configuration was straightforward and I can now listen to Roon on the go. Thanks a lot for this very good work!

1 Like

I use udp-proxy-2020 to access Roon on my phone and laptop (road warrior), across multiple VLANs at home (work laptop is on it’s own VLAN), and another Wireguard instance/tunnel to a RasPi running the Roon Linux client on my desk at work. Honestly, I consider those to be the “basic scenarios”. :slight_smile: I’ve also tested site-to-site VPNs in my home lab, but it’s not something I’ve really used personally.

Working across these “basic scenarios” is to be expected since RoonBroadcastRelay shares the same critical design feature with udp-proxy-2020 - maintaining the Source IP of the original host when forwarding packets. This is of course required for even the client to load the Roon UI (not just be discovered as an audio endpoint), because it will make multiple HTTP connections to the Roon core/server on various ports for artwork, playlists, control zones, etc. and it learns the IP address of the Roon server to connect to via the Source IP during discovery. I mean, I guess you could make it work with NAT rules or something? But, ew gross!

Anyways, it always nice to see more options available for people to try to solve this problem, and I’ll be curious to see how raw sockets work out long term for you (udp-proxy-2020 uses lower level frame injection via PF_PACKET/BPF). But, I’d appreciate it if you focused on how great your solution is without the negative sounding (and frankly inaccurate) commentary on other people’s work.

Finally, one advantage I believe RoonBroadcastRelay will have is by using raw sockets, it should be compatible with a wider variety of IPSec configurations/deployments than udp-proxy-2020.

Best,
Aaron

Hi Aaron,

You are right about that sentence, it was unfair and objectively false… Sorry about that; I am removing it.

Those scenarios make sense as the baseline Roon cases. RoonBroadcastRelay is much narrower in scope: Roon-only, written around my own WireGuard setup, with an explicit relay-to-
relay tunnel because that matched the topology I wanted to run.

On Source IP preservation, I agree. I also do not think NAT is a real substitute for it. Once discovery causes Roon to learn the wrong peer address, fixing only UDP/9003 is not
enough; making the later connections line up through NAT would be fragile.

Implementation-wise, I chose UDP/raw sockets because I wanted the firewall/routing layer to deliver packets to the relay, and then have the relay re-emit them locally while
preserving the original source metadata. udp-proxy-2020’s PF_PACKET/BPF approach is clearly lower-level and more general for interface-based forwarding.

On raw sockets long term: so far it has been stable for me. I have been running the most complex setup from the EXAMPLES.md, which is literally my home setup, in production for about
five months, and it has not caused issues with any of my devices. Of course that is only one environment, so I am still curious to see how it behaves across other VPN
deployments.

Thanks for the detailed feedback.

Best,
Simone

@Rugby It seems I’m not allowed to edit the first message anymore. Can you help me ?

1 Like

We all get carried away at times. Definitely multiple ways to skin the cat and glad to see you took a different approach. Never really occurred to me to worry about the other protocols so it’s great to see that option be available to people who might find that useful.

FWIW, I didn’t mean raw sockets wouldn’t work “long term” in your service… that I have no doubt it will work quite well for you. More of a question how raw sockets work across operating systems and various network situations. I think raw sockets have some interesting advantages in some situations, but also it’s not a clear win in every environment. But as The Dude once said, “that’s just like, your (or rather my) opinion man”. :smiley:

One of these days, I’d love to find time to do a proper Roon aware router that supports NetBird, Tailscale, etc, because I think that would be really interesting (and solve the CG-NAT issue that traditional Wiregard/OpenVPN/etc have challenges with), but alas I don’t think it will ever happen.