Access Plex behind CGNAT

May 26, 2024

Since my home network is behind CGNAT, here are two options that have worked for me to use Plex outside my home network.

Index

Plex and CGNAT

I use Plex on my Windows desktop at home for hosting media. However, my network is behind a CGNAT (Carrier-Grade Network Address Translation) (read: 1 2 3 4). CGNAT allows ISPs to assign the same public IP address to multiple customers by giving each customer a unique private IP within the ISP’s network​​. This setup makes it impossible to use traditional port forwarding for external access, complicating remote streaming and access to my media library​.

To work around CGNAT, you can use a VPN, set up a reverse proxy, or use third-party services that support CGNAT environments to make your Plex server accessible from outside your network. Additionally, you can ask your ISP for a static IP. They may be able to provide one for a fee.

Our options

To work around CGNAT, I use a combination of Tailscale and Bore. This ensures that I can access Plex within my home, within a trusted network (all of my devices when I’m traveling), and even on public networks when I’m at somebody else’s home.

I’ll explain a bit about what Tailscale and Bore do, along with their pros and cons, which eventually balance out.

Tailscale

Tailscale is a mesh VPN using the WireGuard protocol that allows you to connect all of your devices directly to each other. Tailscale supports bi-directional communication, but for Plex, we only need it to be one-way.

flowchart TD
   subgraph Tailscale_and_Home_Network["Tailscale & Home Network"]
    A[Laptop] ---> B[Plex Server]
    C[Phone] ---> B
    D[Tablet] ---> B
    E[TV] ---> B
   end
  

Pros and cons

Bore

Bore is a tool for creating TCP tunnels between two devices. If one of the devices (the Bore server) is accessible via the internet, you can use Bore to make any local port on your desktop (Bore client) publicly accessible.

flowchart TB
    subgraph Tailscale_and_Home_Network["Tailscale & Home Network"]

    A[Laptop] --> B[Plex Server/Bore Client]
    C[Phone] --> B
    D[Tablet] --> B
    E[TV] --> B
    end

    F[Bore Server] <--> B

    subgraph Friends_and_Family["Friends & Family"]
    G[TV]
    end

    G --> F
  

Pros and cons

Setup Bore

Tailscale is fairly straightforward to set up, so I will focus on setting up Bore in this post.

To set up Bore, I will first download Bore on my Plex server (which is my Windows desktop). Then, I will create a VPS and set up the Bore server on it. Next, I will test if my desktop (Bore client) is able to connect to the Bore server. Once the initial testing is complete, I will set up the Bore server and client as background services so that I don’t have to worry about starting them when I reboot or ensuring they’re always online.

I have used several variables in this guide, a summary of which is given below. Please replace these as you see fit:

VariableDescription
[[boreSecret]]A secret string used by the Bore server and client to authenticate. This ensures random Bore clients do not connect to your server.
[[remotePlexPort]]The port used for accessing Plex from the new VPS.
[[vpsIpAddress]]IP address of the VPS you are running the Bore server on.
[[yourUsername]]Your username on your Windows desktop.

Create a VPS

Create a VPS on a cloud provider or another VPS provider in a location close to where your Plex server is. I see Vultr has a VPS close to me in Delhi so I’ll create one there. If you want to use Vultr as well, you can sign up using my referral link and get some free credit.

Download Bore

Download Bore from GitHub depending on your platform. I will pick Ubuntu (x64) for my Bore server and I use Windows 11 for my Plex server.

On Windows (Bore client)

Download and save the .exe as C:\Users\[[yourUsername]]\bore.exe.

On Ubuntu (Bore server)

Download and place bore in /usr/local/bin.

wget -qO- https://github.com/ekzhang/bore/releases/download/v0.5.0/bore-v0.5.0-x86_64-unknown-linux-musl.tar.gz | tar -xz -C /usr/local/bin bore

Ubuntu 24 on Vultr comes with ufw set up, so I will whitelist the additional ports I need:

$ ufw allow 7835/tcp
$ ufw allow [[remotePlexPort]]/tcp
$ ufw reload
$ ufw status
Status: active

To                              Action      From
--                              ------      ----
22/tcp                          ALLOW       Anywhere
7835/tcp                        ALLOW       Anywhere
[[remotePlexPort]]/tcp          ALLOW       Anywhere
22/tcp (v6)                     ALLOW       Anywhere (v6)
7835/tcp (v6)                   ALLOW       Anywhere (v6)
[[remotePlexPort]]/tcp (v6)     ALLOW       Anywhere (v6)

Test the connection

Now that Bore has been downloaded on both the client and the server, we will test to see if we can connect to Plex over the VPS’s IP address. As long as both the client and server are running, we will be able to connect to Plex using the VPS’s IP address.

On Windows, open Terminal and run the following command:

C:\Users\[[yourUsername]]\bore.exe local 32400 --to [[vpsIpAddress]] --secret [[boreSecret]] -p [[remotePlexPort]]

On your Ubuntu server, run the following command:

bore server --secret [[boreSecret]]

In your browser, use the new IP/port combination (http://[[vpsIpAddress]]:[[remotePlexPort]]) to access Plex and add this URL to “Custom server access URLs” by going to the “Settings” > “Network” page.

Screenshot of Plex network settings showing the custom server access URLs and list of IP addresses and networks allowed without authentication.

If you’re now able to stream on Plex using a public network, the tunnel works.

Setup Bore as a service

We will set up Bore to run as a service so that it runs perpetually without needing to be manually monitored.

We’ll create a systemd service for the Bore server to run on Ubuntu, and a Windows service using nssm for the Bore client.

Bore server

We already have bore in /usr/local/bin/bore. We will now create a systemd service that will keep the Bore server running.

Create the systemd service:

nano /etc/systemd/system/bore.service

Add the following content to the service file:

[Unit]
Description=Bore Server
After=network.target

[Service]
ExecStart=/usr/local/bin/bore server --secret [[boreSecret]]
Restart=always
User=nobody
Group=nogroup
WorkingDirectory=/usr/local/bin

[Install]
WantedBy=multi-user.target

Reload systemd and start the service:

systemctl daemon-reload
systemctl start bore
systemctl enable bore

Check the status of the service:

systemctl status bore

Bore client

Download nssm and start PowerShell:

nssm install BoreService

A GUI will open where you can specify the path to bore.exe and its parameters.

Path: C:\Users\[[yourUsername]]\bore.exe

Startup directory: C:\Users\[[yourUsername]]\

Arguments: local 32400 --to [[vpsIpAddress]] --secret [[boreSecret]] -p [[remotePlexPort]]

Start the service:

nssm start BoreService

Test the connection

Verify on Ubuntu that you’re receiving traffic on Bore with service bore status:

● bore.service - Bore Server
     Loaded: loaded (/etc/systemd/system/bore.service; enabled; preset: enabled)
     Active: active (running) since Sun 2024-05-26 01:51:44 UTC; 4min 26s ago
   Main PID: 879 (bore)
      Tasks: 2 (limit: 1061)
     Memory: 2.2M (peak: 2.4M)
        CPU: 47ms
     CGroup: /system.slice/bore.service
             └─879 /usr/local/bin/bore server --secret [[boreSecret]]

May 26 01:51:44 plex systemd[1]: Started bore.service - Bore Server.
May 26 01:51:44 plex bore[879]: 2024-05-26T01:51:44.358256Z  INFO bore_cli::server: server listening addr=0.0.0.0:7835
May 26 01:53:59 plex bore[879]: 2024-05-26T01:53:59.022237Z  INFO control{addr=x.x.x.x:xxxx}: bore_cli::server: incoming connection
May 26 01:53:59 plex bore[879]: 2024-05-26T01:53:59.668826Z  INFO control{addr=x.x.x.x:xxxx}: bore_cli::server: new client port=[[remotePlexPort]]

That’s it!

Bonus

Using a VPN

If you’re using a VPN that supports split tunneling (see: 1 2), add the Bore client (C:\Users\[[yourUsername]]\bore.exe) to the “whitelist” so that it does not use the VPN.

Improve the Remote Streaming Experience

Improve the Transcoder Settings

When you enable remote streaming, it’s essential to reduce bandwidth utilization as much as possible. Here are the network settings I use on my Plex server to minimize buffering. You can access this page by going to “Settings” > “Transcoder” and clicking on “Show Advanced”.

Screenshot of Plex transcoder settings showing options for transcoder quality, temporary directory, throttle buffer, and various transcoding and hardware acceleration settings.

Note: Change the “Transcoder temporary directory” if you have a fast disk that you prefer to use. In my case, this is an NVMe SSD.

Adjust Streaming Quality Settings

If you face connectivity issues or there’s a lot of buffering while streaming remotely, you should set the maximum bandwidth that can be used for streaming on the device you are streaming from, especially if the internet connection is slow. This must be set up using the same user profile and on the same device where you are facing connectivity issues.

The screenshot below is for Plex web settings, which can be accessed by going to “Settings” > “Plex Web.” For other devices, this will vary slightly. Note that checking “Automatically adjust quality (Beta)” doesn’t really do much and is fairly ineffective, so I’ve set the maximum streaming quality to 8 Mbps. This means that whenever I stream, the video will not exceed 8 Mbps by default (but can still be adjusted on an individual basis).

Screenshot of Plex Web Quality settings showing options for automatically adjusting quality, internet streaming video quality, and home streaming video quality.