VPN and IPTV (multicast)

Hey guys.
My Specs: RB5009UPr+S+ , RouterOS 7.14 stable.

What I already have achieved in terms of OpenVPN and IPTV is:

  • Static interface for my only OVPN/PPP user. I think it makes firewalling etc. much more easier, if you can address a configuration item to something which statically exists.


  • Can access ressources running on the router (SSH, Samba, PING)


  • Can access ressources on the pushed ip subner / VLAN


  • IPTV runs great on my local VLAN-34 (all wired and wireless users by default are in) mapped to the only bridge interface “BR1”. I do run IGMP Proxy on that VLAN and the “BR1” interface runs also IGMP Snooping.

What I was not able to achieve is to run IPTV on my OVPN connected maschine. I tried everything basic, went through forums, even thoug nut much was to find. Pushed also the 232.0.0.0/8 to the OVPN Client, which looks good and shows up in the ipv4 routing table. But the IGMP Proxy counters for the OVPN interface are not incrementing.

Do you got any hints, where to look?

Thanx guys

I’m currently running version 17.8.2 and have switched from OpenVPN to WireGuard. Unfortunately, WireGuard, like OpenVPN, does not support multicast forwarding.

To work around this, I considered setting up a small Debian-based Linux server (LinuxPC) connected to my MikroTik router. The LinuxPC would act as a proxy using the udp-proxy-2020 service. Instead of connecting the RemotePC directly to the MikroTik router via VPN, the RemotePC would establish a Wireguard VPN session with the LinuxPC instead — something that’s relatively easy to set up and it works without problems.

The idea is that the LinuxPC would join the multicast group on behalf of the RemotePC, convert the multicast traffic to unicast, and then send it through the WireGuard tunnel to the RemotePC. However, I’m struggling to get this working properly.

Has anyone successfully implemented a similar setup?

If you have a mikrotik at both ends you could put an EoIP tunnel within the wireguard VPN and bridge that with the LAN on both ends…
If you are just running a road warrior config then I think you are SOL.

Just use pure ethernet over l2tpv3/vxlan/eoip between LinuxPC and MT.

Have you considered UDPXY (it’s extremely lightweight and run great in container on RouterOS, I use it on my RB5009 and hAP ac² with only 128MB RAM)? It will introduce a few seconds delay to the streams but other than that, it works well, even for watching IPTV channels on the go over WireGuard. I now exclusively use that for watching IPTV in my local networks instead of multicast because IGMP Snooping on the RB5009 still doesn’t work correctly with VLANs + IPv6. IGMP Proxy is only needed between the upstream interface and the container bridge that has the VETH interface.

As a newbie I tried to run ppptran/udpxy-mikrotik container on my Mikrotik with following step-by-step:

  1. /system/device-mode/update container=yes
    [rt@fw] > /system/device-mode/ print
    mode: advanced
    allowed-versions: 7.13+,6.49.8+
    ...
    container: yes

  2. /interface/veth/add name=veth1-containers address=192.168.221.2/24 gateway=192.168.221.1
    [rt@fw] > /interface/veth/ print
    Flags: X - disabled; R - running
    0 name="veth1-containers" address=192.168.221.2/24 gateway=192.168.221.1 gateway6=""

  3. /interface/bridge/add name=BR-containers
    [rt@fw] > /interface/bridge/ print
    Flags: D - dynamic; X - disabled, R - running
    0 R name="BR-containers" mtu=auto actual-mtu=1500 l2mtu=65535 arp=enabled arp-timeout=auto mac-address=CE:23:15:1D:17:80 protocol-mode=rstp fast-forward=yes igmp-snooping=no auto-mac=yes
    ageing-time=5m priority=0x8000 max-message-age=20s forward-delay=15s transmit-hold-count=6 vlan-filtering=no dhcp-snooping=no port-cost-mode=long mvrp=no max-learned-entries=auto

1 R name="BR1" mtu=auto actual-mtu=1500 l2mtu=1514 arp=enabled arp-timeout=auto mac-address=78:9A:18:8B:BA:39 protocol-mode=rstp fast-forward=yes igmp-snooping=yes multicast-router=temporary-query
multicast-querier=yes startup-query-count=2 last-member-query-count=2 last-member-interval=1s membership-interval=4m20s querier-interval=4m15s query-interval=2m5s query-response-interval=10s
startup-query-interval=31s250ms igmp-version=2 mld-version=1 auto-mac=yes ageing-time=5m priority=0x8000 max-message-age=20s forward-delay=15s transmit-hold-count=6 vlan-filtering=yes
ether-type=0x8100 pvid=99 frame-types=admit-all ingress-filtering=yes dhcp-snooping=no port-cost-mode=short mvrp=no max-learned-entries=auto

  1. /ip/address/add address=192.168.221.1/24 interface=BR-containers
    [rt@fw] > /ip/address/ print
    Flags: D - DYNAMIC
    Columns: ADDRESS, NETWORK, INTERFACE
    # ADDRESS NETWORK INTERFACE
    ...
    6 192.168.221.1/32 192.168.221.1 BR-containers

  2. /container/config/set registry-url=https://registry-1.docker.io tmpdir=usb1/docker_tmp

  3. /container/add remote-image=ppptran/udpxy-mikrotik:arm64 interface=veth1-containers root-dir=usb1/containers/udpxy logging=yes
    [rt@fw] > /container/print
    0 ;;; Process exited with status 255
    name="udpxy-mikrotik:arm64" repo="registry-1.docker.io/ppptran/udpxy-mikrotik:arm64" os="linux" arch="arm64" interface=veth1-containers root-dir=usb1/containers/udpxy mounts="" workdir="/"
    logging=yes start-on-boot=yes status=stopped

I tried to start it several times, but it lasted always like 1-2 seconds and then stopped with "255" error. The Log shows:

2025-09-21 09:43:10 container,info,debug importing remote image
*2025-09-21 09:43:10 system,info item added by winbox-3.41/tcp-msg(winbox):rt@192.168.34.101 (3 = /container add dns="" file="" interface=veth1-containers logging=yes mounts="" remote-image=ppptran/udpxy-mikrotik:arm64 root-dir=usb1/containers/udpxy start-on-boot=yes)
2025-09-21 09:43:12 container,info,debug [cont] getting layer sha256:d69d4d41cfe2ee680d6972795e2a1eb9e4dc4ec3b3c5e0797c9ab43bb3726fa7
2025-09-21 09:43:13 container,info,debug [cont] layer sha256:d69d4d41cfe2ee680d6972795e2a1eb9e4dc4ec3b3c5e0797c9ab43bb3726fa7 downloaded
2025-09-21 09:43:13 container,info,debug [cont] getting layer sha256:78595cae4b6d0d4731c815311f763a18966f17796935c17a0f512f20a87b693a
2025-09-21 09:43:14 container,info,debug [cont] layer sha256:78595cae4b6d0d4731c815311f763a18966f17796935c17a0f512f20a87b693a downloaded
2025-09-21 09:43:14 container,info,debug [cont] getting layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1
2025-09-21 09:43:14 container,info,debug [cont] layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 downloaded
2025-09-21 09:43:14 container,info,debug import successful, container a6a95c5d-adbf-427d-9d68-52f67666a0c0
2025-09-21 09:43:37 interface,info veth1-containers detect LAN
2025-09-21 09:43:37 container,info,debug container udpxy-mikrotik:arm64 started
2025-09-21 09:43:37 container,info,debug container udpxy-mikrotik:arm64 exited, status: 255
2025-09-21 09:43:40 container,info,debug container udpxy-mikrotik:arm64 started
2025-09-21 09:43:40 interface,info veth1-containers detect LAN
2025-09-21 09:43:40 container,info,debug container udpxy-mikrotik:arm64 exited, status: 255

Any hint what I did wrong here? Thanx

Ohh the status: 255

You need to delete the existting Root Dir folder when creating container in File.

Let RouterOS creates the Root Dir folder automatically. Do not manually create it in the File , and assign it to the container. It will cause error 255.

You're a genius man! This approach helped and now:

[rt@fw] > /log/print where message~"container"
2025-09-22 07:46:16 interface,info veth1-containers link up
2025-09-22 07:46:16 system,info device added by ssh:rt@192.168.34.101 (*17 = /interface veth add address=192.168.221.2/24 gateway=192.168.221.1 name=veth1-containers)
2025-09-22 07:46:38 bridge,info "BR-containers" mac address changed to 8E:67:D4:1D:5B:FB
2025-09-22 07:46:38 interface,info BR-containers detect LAN
2025-09-22 07:46:39 system,info device added by ssh:rt@192.168.34.101 (*18 = /interface bridge add name=BR-containers)
2025-09-22 07:48:33 system,info address added by ssh:rt@192.168.34.101 (*C = /ip address add address=192.168.221.1/24 interface=BR-containers)
2025-09-22 07:49:04 system,info container changed by ssh:rt@192.168.34.101 (/container config set registry-url=https://registry-1.docker.io tmpdir=usb1/docker_tmp)
2025-09-22 07:49:21 system,info item added by ssh:rt@192.168.34.101 (*4 = /container add interface=veth1-containers logging=yes remote-image=ppptran/udpxy-mikrotik:arm64 root-dir=usb1/containers/udpxy)
2025-09-22 07:49:25 container,info,debug import successful, container c93dfb7c-430f-4877-a832-b72fe074da3c
2025-09-22 07:50:04 container,info,debug container udpxy-mikrotik:arm64 started
2025-09-22 07:50:04 interface,info veth1-containers detect LAN

Three more questions to this implementation:

Given that:

  • interface 'veth1-containers' = 192.168.221.2
  • interface bridge 'BR-containers' = 192.168.221.1
  • ZeroTier which I am using for RA-VPN connecting my PC to MIkrotik @home interface = 192.168.192.100
  1. What Multicast IP should I put into VLC running on the VPN enabled PC, when for example this multicast IP has worked without using UDPXY (but of course stuterry, because of what I am implementing UDPXY in the first place): 'rtp://@239.200.80.15:5000'

  2. Should I enable IGMP proxy for some (or all) of the newly created container interfaces?

  3. Are there any Firewall policies needed for this communication to work?

This is how i did it on mine.

My ISP provide IPTV rtp/udp via vlan 2420.

so, vlan 2024 is one interface.

veth1-containers is IP of udpxy : 192.168.221.2
BR-containers = 192.168.221.1
make sure that you must add the veth1-containers to the BR-containers in Bridge -> Port.

Then, in the Routing -> IGMP Proxy, this is how it's done:
Create new:
-> Interface = vlan 2420 ( the source of rtp/udp that isp give you)
-> Threshold =1
-> Alternative Subnet = 0.0.0.0/0
Select : Upstream
Then select ok.

Create new:
-> Interface= BR-containers
-> Threshold=1
-> Alternative Subnet : note this, do not add anything in here, leave it empty as is.
-> Upstream : Leave it UNCHECKED // it means that this is the Querrier
Then select ok.

Create new:
-> Interface : BR-LAN ( whatever your LAN bridge is )
-> Threshold=1
-> Alternative Subnet : note this, do not add anything in here, leave it empty as is.
-> Upstream : Leave it UNCHECKED // it means that this is the Querrier
Then select ok.

Run the udpxy container.
Now, in your LAN bridge ( which is 192.168.192.1/24 subnet)
connect your computer to this subnet.
Open VLC and then run the m3u list as this format:

http:// ip of udpxy container : port / rtp / ip of that channel : port of that channel

http://192.168.221.2:4000/rtp/ 239.200.80.15:10254

So , we have 192.168.221.2 is the ip of udpxy container.
4000 is the port of ppptran/udpxy-mikrotik container.
and 239.200.80.15 is the ip of channel 1 ( for example) and then 10254 is the port of that channel.

Also, i did in my firewall:
Filter rule

  1. chain = input -> protcol = udp -> in-interface = vlan2420
  2. chain = forward -> protocol = udp -> in-interface=vlan2420
  3. chian=input -> protocol = igmp -> in-interface=vlan2420

then, these 3 rules is on the top of the firewall list. ( your case, make sure to test with protcol rtp)

1 Like

In addition to what @ppptran wrote above:

  • In the URLs to the streams, if the video player apps dislike having two : in the URL, you can replace the last : with characters like -. So instead of http://192.168.221.2:4000/rtp/239.200.80.15:10254 you can use the link http://192.168.221.2:4000/rtp/239.200.80.15-10254. Allowed replacement characters include %, ~, +, -, ^. But normally in URL % and + are special and need to be encoded, so stick with - for simplicity.

  • The UDPXY status page can be reached at http://ip:port/status/ (update IP and port to match).

  • The UDP rule on chain input should be limited to dst-address=224.0.0.0/4 and the action should be drop, and the rule should be move up (but still below the accept established/related rule of the input chain). The router itself doesn't need to consume any of those multicast packets coming from the vlan2420 interface, and we can omit this rule too without any difference. But we drop them early so that the other parts later in the chain don't have to deal with these packets.

  • The accept UDP rule on the forward chain is necessary, but here you can add dst-address=224.0.0.0/4 to further limit the rule to multicast, not accepting other things such as DNS queries.

So everything works. What I had to set additionaly:

  1. Since the free version of ZeroTier does not allow to route more than a single subnet, I needed to statically route on the ZeroTier client (Win11 PC) the Mikrotik container network 192.168.221.0/24 via the ZeroTier interface on this computer.

  2. In terms of Mikrotik FW rules, I have set following (include also ZeroTier relevant ones):

  • INPUT: ALL protocols > SRC Addresses = the /24 given or set on the ZeroTier dashboard for my VPN network > IN Interface = zerotier1
  • INPUT: UDP (17) > IN Interface = ether1 (my WAN/ISP interface)
  • INPUT: IGMP (2) > IN Interface = ether1
  • FORWARD: UDP (17) > IN Interface = ether1 > OUT Interface = BR-Containers
  • FORWARD: ALL > IN Interface = BR-Containers > OUT Interface = zerotier1
  • FORWARD: ALL > IN Interface = zerotier1 > OUT Interface = BR-Containers

One thing I am not able to cover is to leave the multicast group immediately when channel is stopped in VLC for example. For classic multicast streams it works, but once it goes through the UDP Proxy container, it does not work and I have to wait until the ISP recognizes that there are no subscribers wanting to consume this certain stream and traffic stops.

But thank you guys for this help.