Running a Plex server through Starlink CGNAT with Mullvad VPN

If you run a Plex server and wish to be able to stream in quality above 720p you will need to establish direct connectivity with one of their endpoints. At the time of writing this article, Plex permits up to 1 Mbps throughput via their indirect streaming relays, which is insufficient for 1080p streams.

I have a friend who has relocated from living in the city to the country, out of range from conventional broadband providers. In the city, he had a high-speed fiber-optic connection and ran a Plex server with a library of almost 100TBs in size. Recently Starlink became available, and he signed up for their services. He saw that the speeds they offered would allow him to get his Plex server streaming again.

We found the latency to a server in Toronto was an average of 38ms, which is great for satellite internet. The package seemed perfect until he discovered that a direct connection could not be established to Plex.

This was because Starlink customers are behind Carrier Grade Network Address Translation (CGN or CGNAT). This meant that customers were sharing IP addresses, and did not have externally accessible ports. Some carriers utilize CGNAT and still have working port-forwarding solutions through using Port Control Protocol (RFC6887), however, this was not the case here. I don’t know if they have plans for a solution down the road or if their infrastructure will remain as is, but I recommended for my friend to work around it using a VPN service which allows port-forwarding.

The setup would be simple, using Mullvad VPN, he would pick a local endpoint, add a forwarded port, and change the settings on Plex to manually specify the port.

I got him to set up ngrok to get around the CGNAT and logged into his server, established the VPN tunnel, and confirmed that the Mullvad assigned port-forward was working.

Established VPN Tunnel

mullvad-ca23: flags=209  mtu 1420
         inet 10.67.109.247  netmask 255.255.255.255  destination 10.67.109.247
         inet6 fc00:bbbb:bbbb:bb01::4:6df6  prefixlen 128  scopeid 0x0
         unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 1000  (UNSPEC)
         RX packets 15665  bytes 5564880 (5.5 MB)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 17203  bytes 2800120 (2.8 MB)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Mullvad provided 60856/TCP as the port-forward for our tunnel

# nc -l -k 60856 -vn
 Listening on 0.0.0.0 60856
 Connection received on XXX.XXX.XXX.XXX 58499

Everything looked good, however upon setting 60856 as the manually specified port in Plex, it still did not work.

Plex was attempting to connect to the manually specified port on our VPN IP, where nothing was listening. The Plex server had remained bound to port 32400.

Why was this happening? This was occurring because the app he was using to set the manually specified port would attempt to connect to the Plex server on port 32400 to make the changes. For this change request to go through, I applied a simple iptables rule, which would allow for the app to connect and set our new manually specified port:

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 60856 -j REDIRECT --to-ports 32400

Once this rule is added, the request to set a new port will go through, and the rule will need to be removed:

iptables -t nat -D PREROUTING -p tcp -m tcp --dport 60856 -j REDIRECT --to-ports 32400

Following this, the Plex UI should indicate that your server is reachable from outside your network, and you should have direct connectivity from behind CGNAT through a VPN hop.

3 Replies to “Running a Plex server through Starlink CGNAT with Mullvad VPN”

  1. Thanks for great article. As it is now very trending to use Starlink, is there a way to calculate if the Starlink service will be available on in my area? How can I calculate this master?

Leave a Reply

Your email address will not be published. Required fields are marked *