Well, I've spent the better half of two weeks trying to get my VPN service to run the way I want to, so I thought I'd put together a little how to to help others.
Please note: I will be putting a more detailed version on my website once I get it updated (I'll let you know here when I do).
A Little background and common problems people have with running a VPN. I've done a lot of research and found a lot of people having the same questions as I did. I will focus this tutorial specifically on getting Plex up and running with the VPN.
Question 1: "Once I turn on my VPN, I can't access my server outside my home network (remote access) / This goes for Plex too.
Answer 1: When you run a VPN you are creating a "new" encrypted connection to the web. Since you are bypassing your ISP, unless your VPN provider has open ports (most of them do not for security reasons), then you will no longer have access to your services that you port forwarded at home. There are two options to solve this problem.
Option A: see if your VPN provider has the option to open ports, if they do, then follow their support, open a port, then port forward the service you want to use remotely through that port. There are a couple of problems with this option. First, if you are opening a port through the VPN, you are lowing the level of security that you signed up for in the first place. Another issue is that even if your VPN provider can open a port for you, it will most likely only be one, so if you have multiple services you are trying to access remotely, you are out of luck. Finally, accessing Plex remotely with a VPN on requires more than just having a port open through the VPN tunnel (I'll explain more in a minute).
Option B: This is the option I recommend, and have working on my setup at home. Use a "Split Tunnel"/Create a "Routing Policy". What this means is that you would use iptables to selectively route your traffic either through the VPN or directly through your ISP. This includes allowing traffic to flow to ports you have open on your router.
Question 2: "I setup a Split Tunnel, and can successfully access my server outside my home network, but I still can't access Plex".
Answer 2: Well, for some reason (that others could probably better explain than I can), because Plex is a "connected service" where it requires to talk to PMS behind your firewall, you not only need to get port 32400 to bypass the VPN, but you also need to allow any traffic from the IP addresses associated with plex.tv to also bypass the VPN.
Okay, let's move on...one more thing before I dig in:
Things you need for this to work:
1. You must have a router that is running an open source firmware (like DD-wrt or Tomato etc.) that supports iptables.
2. I would recommend that you have your modem set to "Bridged" mode and let your router handle your ISP traffic. To see
if your modem is in "Bridged" mode, go to google.com and type: "what is my ip address" in the search bar. Google will return your public IP addresss.
See if this matches your WAN IP address on your router. If it does, then you are good to go. If not, then that potentially means that your modem is also routing traffic to your router, which means you are running a "double NAT".
You probably won't have much issue if you are just surfing the web and don't need remote access, but if you do, this could cause you some headaches...
3. This is a BIG one for those of you who have a NAS like Synology or QNAP that can run a VPN client.
I would recommend that you run your VPN client on your router NOT the NAS!
Unfortunately, these servers don't usually support any kind of routing policy (iptables), and if you setup
to route your traffic ahead of your vpn client in your network chain, this can also cause lots of problems.
I had started this "journey" by running the VPN client on my Synology server, then discovered the routing issues. An addition problem with running the VPN client on Synology boxes
(This appears to be a bug in the current DSM), when your router reboots (I have mine shut down at night) the VPN client doesn't automatically reconnect on startup.
So if you are unaware of this, you could be potentially running services in the open without knowing it.
4. If you are accessing your network remotely, then chances are you are using a DDNS service to update your domain. I would recommend that you also run the DDNS client on your router and not on your NAS. Again, if you have your DDNS behind your VPN client in your chain, you could also have trouble.
To make plex work remotely you have two basic things that need to be done:
1. Create a routing policy to open necessary ports
2. Create a way to dynamically route plex.tv ip addresses around the vpn
(note: both of these steps are available in multiple places on the web. #2 is available in the following post on this forum: https://forums.plex.tv/topic/64600-using-plex-server-with-a-vpn/page-4
I want to give credit to zanechua. The solution I put to use to update the plex.tv ip addresses came from that post.
1. ROUTING POLICY
place the following code into your firewall script of DD-wrt or WAN-UP (I believe) of Tomato etc.
The Variable PlexServer should be the server that has your Plex on it.
The logger statements were simply added to put notes in the log (if you run syslog these will show up).
This policy was designed to make sure traffic that is going to ports that are bittorrents on my Synology server get dropped should the VPN go down.
If you don't care about that, you can comment out the line that has the $BitTorrentPortList variable
Modify the $ByPassPortList variable to have the ports that you'd like bypass the VPN. Notice 32400 is on the list (Plex). All the other ports are services that I use on my Synology NAS.
Important NOTE: On some versions of DD-wrt, if you make changes to your router and click "apply changes" but don't reboot, your vpn connection will stop. (this happens to me with build 18777). In this case you can either add a script with cron that checks the status of the vpn and restarts it automatically if it sees it's down or simply make sure that you reboot the router when making changes...
#!/bin/shScript to route traffic from home network through VPN selectively.
Based off the discussion at http://www.smallnetbuilder.com/forums/showthread.php?t=9311
The setup is a Roku box, a Home PC running Plex, and a Synology NAS with a torrent client running a web interface.
The aim is to have all traffic from Roku go through the VPN, all traffic from the Home PC (and all other devices) bypassing the VPN,
and the Synology NAS using the VPN. There are however some exceptions. Since Plex uses port 32400, Roku has to bypass the VPN when
using that port. In addition, port 9091 has to bypass the VPN as well in order to access the Synology torrent client. Lastly, ports 5000
and 5001 has to bypass the VPN for the Synology Management UI.
Requirements: Asuswrt-Merlin with OpenVPN already set up
logger -t “($(basename $0))” $$ ExpressVPN Selective Customization Starting… " 0{:+ $}."
PlexServer=“192.168.1.XXX”
ByPassPortList=“32400,5000,5001,5100,5101,5005,5006,5010,6690,8001,8801,7101,7001”
BitTorrentPortList=“16881,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890”SHELL COMMANDS FOR MAINTENANCE.
DO NOT UNCOMMENT, THESE ARE INTENDED TO BE USED IN A SHELL COMMAND LINE
List Contents by line number
iptables -L PREROUTING -t mangle -n --line-numbers
Delete rules from mangle by line number
iptables -D PREROUTING type-line-number-here -t mangle
To list the current rules on the router, issue the command:
iptables -t mangle -L PREROUTING
Flush/reset all the rules to default by issuing the command:
iptables -t mangle -F PREROUTING
Disable Reverse Path Filtering on all current and future network interfaces:
for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
echo 0 > $i
doneDelete table 100 and flush any existing rules if they exist.
ip route flush table 100
ip route del default table 100
ip rule del fwmark 1 table 100
ip route flush cache
iptables -t mangle -F PREROUTINGCopy all non-default and non-VPN related routes from the main table into table 100.
Then configure table 100 to route all traffic out the WAN gateway and assign it mark “1”
tun_if=“tun0”
ip route show table main | grep -Ev ^default | grep -Ev $tun_if
| while read ROUTE ; do
ip route add table 100 ROUTE logger -t "((basename $0))" $$ ExpressVPN Table 100 added entry: $ROUTE
doneip route add default table 100 via $(nvram get wan_gateway)
ip rule add fwmark 1 table 100
ip route flush cacheBy default all traffic bypasses the VPN
iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 1
logger -t “($(basename $0))” $$ Selective customisation for: "$"PlexServer PlexServer
By default Synology uses the VPN, and FORCES the use of the VPN tunnel except ports needing access from outside LAN
MediaVault Server
iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range $PlexServer -j MARK --set-mark 0
#Just drop packets to Bit Torrents should the VPN go down
iptables -I FORWARD -i br0 -s $PlexServer -o eth0 -m multiport --port $BitTorrentPortList -j DROP
iptables -I FORWARD -i br0 -s $PlexServer -o eth0 -p tcp -m multiport --port $ByPassPortList -j ACCEPTlogger -t “($(basename $0))” $$ Routing ports to bypass VPN on all Devices:
#ports to bypass the VPN for all available devices
iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --port $ByPassPortList -j MARK --set-mark 1
#All WOL signal to bypass VPN
iptables -t mangle -A PREROUTING -i br0 -p udp -m multiport --port 9 -j MARK --set-mark 1#Note: Plex.tv static routing is done in startup and cronjob. Updates every 60 minutes
logger -t “($(basename $0))” $$ ExpressVPN Selective Customization completed.
Now this is half the battle for Plex.(and actually the easy part). The other part requires grabbing the ip addresses that plex.tv uses and have them bypass the VPN tunnel. Originally I tried just to add a static list of addresses, but this was cumbersome, and not very reliable. What happens if Plex changes their addresses? You'll have to figure it out all over again. Unfortunately, there really isn't any way to automatically grap ip addresses from a domain. The simplest solution relies on the script that zanechua created. Since DD-wrt and other open source firmware use a different flavor of linux that what he wrote it for, I had to modify it to work for this purpose.
There were a few other issues I discovered trying to implement this script for use on the router.
1. Most of the directories on my DD-wrt router get re-created everytime it reboots. So, if I need to boot the router, I have to copy the script over to the location again.
2. You must make sure the script has executable permissions
3. You will need to have the script run using a cron so that it will run on a regular interval (every hour). That way it will pickup the latest ip and create a static route for it.
4. Depending on your version of DD-wrt you may need to fix the permissions of cron before you can start using it.
To keep things as simple as possible, I decided to have this script get created everytime the router boots up. That way I didn't have to worry about it being wiped everytime.
The permissions are also automatically set properly, and I will include the code to fix cron.
Here's the code for the Plex.tv address updater
################################################## #Create Plex Static Route Script on Startup cat < /tmp/Plex_StaticRoute.sh #!/bin/sh#Fetch Current Server Address for plex.tv
#DNS="(dig plex.tv +short) (dig @8.8.8.8 plex.tv +short) (dig @209.244.0.3 plex.tv +short)" #DD-wrt Friendly logger "Starting Plex static route script..." DNS1=(nslookup plex.tv | tail -1 | awk -F " " '{print 3}') #Google DNS lookup DNS2=(nslookup plex.tv 8.8.8.8 | tail -2 | awk -F " " '{print 3}' | tail -1) DNS3=(nslookup plex.tv 8.8.4.4 | tail -2 | awk -F " " '{print 3}' | tail -1) #Level3.net DNS lookup DNS4=(nslookup plex.tv 209.244.0.3 | tail -2 | awk -F " " ‘{print $3}’ | tail -1)
logger “Grabbing current ipaddresses from plex.tv”
DNS="$DNS1 $DNS2 $DNS3 DNS4" UNIQ_IP=(echo “$DNS” | tr ’ ’ ’
’ | sort -u | tr ’
’ ’ ')
logger “Current registered ip addresses: $DNS”for IP in $UNIQ_IP
do
#Create localroute variable to see if route exists
localroute=route | grep $IP
#Check if route exists
if [[ -z “$localroute” ]]; then
#route doesn’t exist, add route
logger “Route doesn’t exist, creating…”
route add -net “$IP” netmask 255.255.255.255 gwnvram get wan_gateway
logger “New routes using $IP created”
echo $IP
else
#route exists, hurray
logger “Plex static routes exist. Cool!”
echo “yay”
fi
done
logger “Plex static route script complete.”
EOL
chmod +x /tmp/Plex_StaticRoute.sh
/tmp/Plex_StaticRoute.sh
exit 0
Note: you will see at the very bottom of this script that it runs itself when it's done being created. That way, when your router reboots, the plex script runs right away, then cron
takes over...
Again logger comments have been added so you can check the status in syslog or other logs in your router.
if cron is not enabled in the router turn it on now.
put the following in the cron section:
#*/1 * * * * root /usr/bin/logger TESTING THE WEBUI.... #Runs a script every hour to check the ip address of plex.tv and then creates a static route so that it bypasses the VPN */60 * * * * root /bin/sh /tmp/Plex_StaticRoute.sh
Formatting the cron is EXTREMELY IMPORTANT! I accidentally forgot a space and it prevented from cron to work.
A simple way to see if cron is functioning properly, remove the # from the first statement above and save the changes. If cron is working properly you should see "TESTING THE WEBUI..." in your log file or syslog.
If it is, then your permissions are probably set correctly. This is a "dumbed down" test. If you are more adventurous, then you can log into the router and do an ls -al on the cron directories and files and sees what they are currently at. Below is the cron permission fix script. This also goes in the startup section of the router (Administration>Commands) DD-wrt. In the code below you will see the directories and permissions that are necessary.
#!/bin/sh ################################################## #Fix Crontab permission problem #CronFix startup script #Place in WebUI or {opt/jffs}/etc/config/____.startupsleep 60
#Might not be necessary…
stopservice cron#This one keep password same as root, duplicates Shell of root
[ -zcat /tmp/etc/passwd | grep -o crontabs
] && cat /tmp/etc/passwd | grep -m 1 root | sed ‘s/root/crontabs/’>> /tmp/etc/passwd#This one leaves it blank, and is limited to OptWare. Change /opt/bin/bash to /bin/sh otherwise.
#grep -q “^crontabs:” /tmp/etc/passwd || echo 'crontabs::0:0:Contab User,:/tmp/root:/opt/bin/bash’ >> /tmp/etc/passwd
chmod 600 /tmp/crontab
chmod 750 /tmp/cron.d/
chmod 644 /tmp/cron.d/
sleep 1#Might not be necessary…
startservice cron
##################################################
After you have confimed that cron is working you can put the # back in front of the first statement so you aren't stuck with that message appearing every minute.
The Plex_StaticRoute.sh script will run every 60 minutes. That has worked fine for me. Feel free to adjust if you are noticing that plex isn't always connecting to the service, but I think 60 should be plenty.
And that's pretty much it.
I discovered a few caveats which required that I add a couple of more iptable rules.
1. If you are finding that ever so often your internet has stopped working while your VPN is running (I'm running OpenVPN), in my case, it turned out that with the VPN up, notices about DHCP lease renewal weren't getting to my ISP to update my WAN IP Address. Regardless of whether your ISP WAN IP address gets updated, if this doesn't get to them, then your connect could drop. If this is happening to you, do some research on your ISP as to how long their DHCP lease is. Mine is 24 hours with Time Warner. Then divide that in 1/2. That's the amount of time till your next lease update. So, it turned out my internet (this was just internal internet by the way) was dropping at about 12 hours every day...thus the connection.
Put the following iptable statement below your other iptables in the firewall section:
#Fixes Firewall blocking DHCP Renew Responses iptables -I INPUT -p udp --dport 68 -j ACCEPT
2. Another issue I discovered when running my VPN was that if I was inside my LAN (on my home network), but was trying to access my server through my Dynamic DNS domain I couldn't connect. However if I was outside my home network, I could connect just fine. It turns out I had what's called a "NAT loopback". Apparently some builds of DD-wrt have a bug that causes this problem. When my VPN wasn't on, I didn't have this problem. However, when the VPN was on, this was happening to me. The following statement fixed it for me. Also put this in your firewall script:
#correcting NAT loopback problem. Fixes accessing public IP address from within LAN network. This is needed when running OpenVPN (for some reason) insmod ipt_mark insmod xt_mark iptables -t mangle -A PREROUTING -i ! `get_wanface` -d `nvram get wan_ipaddr` -j MARK --set-mark 0xd001 iptables -t mangle -A PREROUTING -i ! `get_wanface` -d 192.168.1.0/24 -j MARK --set-mark 0xd001 iptables -t mangle -A PREROUTING -j CONNMARK --save-mark iptables -t nat -A POSTROUTING -m mark --mark 0xd001 -j MASQUERADE
The line that has "192.168.1.0/24" make sure it matches your LAN IP address. This statement was key to getting this to work for my setup.
I appologize if this tutorial is short on details. If you are struggling with something please feel free to post, and I'll see if I can help. At some point, I'll be putting this on my website in more detail, so hopefully that will answer any questions.
If you see any errors, or bad explanations, please feel free to post corrections (please be constructive) I'm open and happy for any feedback.
I hope this helps someone. It took a lot of time, patience and research to get through this.