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
- Devices are directly connected over a VPN, so while it’s not local, it’s still connected without an intermediary, resulting in minimal latency.
- You do not have to open up any ports publicly or allow traffic from the internet; all users are authenticated.
- Tailscale needs to be set up on every device in use. This means you cannot use another VPN while Tailscale is running, and you cannot access Plex if your device does not support it. This renders Plex unusable on Chromecasts at hotels (Apple TV works though!).
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
- Since Bore will be used outside your home or trusted network, you need to tune the bandwidth on the Plex client and set realistic expectations. Due to the intermediary server between you and Plex, you will experience some latency. To minimize latency issues, have your Bore server as close to the Plex server as possible.
- Requires an additional server to be set up, which can get expensive depending on location and bandwidth requirements.
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:
Variable | Description |
---|---|
[[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.
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”.
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).