[HowTo] Permanent NordVPN tunnel on OSMC

I will describe the method I used to permanently have a connection with NordVPN on my Vero4K, but this should work on any OSMC box.
This method determines the best reachable NordVPN server in or near your country and then connects with it during startup of your machine. When the tunnel is closed for any reason, it will be automatically re-connected, again by first determining the best reachable NordVPN server available. NordVPN’s DNS servers are used by default and DNS queries are sent through the VPN Tunnel to prevent DNS leaking.
All this functionality is actually provided by openpyn and this how-to will describe how to install it on OSMC.

In my opinion, this is the most family-friendly solution, as the VPN is managed completely automatically and transparantly without the need for users to manually start tinkering in an openvpn manager inside Kodi. Only disadvantage that I see is that you also don’t have a status of the connection inside Kodi…

Installation

  • Open a SSH connection to your OSMC box
  • Install dependencies sudo apt install openvpn unzip wget python3-setuptools python3-pip psmisc
  • Install python wheel, required for openpyn install sudo python3 -m pip install wheel --upgrade
  • Install openpyn: sudo python3 -m pip install openpyn --upgrade
  • Execute the openpyn initialization. This will request your NordVPN credentials and store them, download the ovpn configfiles and install a systemd service): sudo openpyn --init
  • For fast ping tests of the NordVPN servers you will require a version of ping that supports -n and -i: sudo apt install iputils-ping
  • Enable the system service to start on boot: sudo systemctl enable openpyn
  • Start the VPN: sudo systemctl start openpyn

Support for downloading torrents
However, if you will be downloading torrents on your OSMC box, you will need to connect to a NordVPN server that actually allows that to prevent being kicked from the server and losing your connection all the time:
Edit /etc/systemd/system/openpyn.service and change the line

ExecStart=/usr/local/bin/openpyn --silent

into

ExecStart=/usr/local/bin/openpyn --p2p --silent

Disable NordVPN DNS
Openpyn also automatically will start using the NordVPN DNS servers, through the tunnel, to prevent DNS leaking. This is a good thing, and you should skip this step if you don’t have an internal DNS server in your network. However if you do have an internal DNS server in your network, you will no longer be able to resolve host-names of your internal network.
In that case, make sure your internal DNS servers forwards external requests to NordVPN DNS servers, preferable also through a NordVPN tunnel, set up on your DNS server itself and change /etc/systemd/system/openpyn.service to include the --skip-dns-patch option to prevent openpyn to manage your DNS resolving:

change

ExecStart=/usr/local/bin/openpyn --silent

into

ExecStart=/usr/local/bin/openpyn be --skip-dns-patch --silent

(of-course, if you already added the --p2p option, you should also leave that option there)

KILLSWITCH
Openpyn also has experimental support for a killswitch, meaning that it won’t allow any traffic going out in the case the tunnel goes down. This can be enabled by adding the -f option to the ExecStart line. I don’t use this option myself, so I cannot give any more details about it. See GitHub - jotyGill/openpyn-nordvpn: Easily connect to and switch between, OpenVPN servers hosted by NordVPN on Linux (+patch leakes) for more information about the kill switch and how to allow a few ports to be accessed from outside (kodi webinterface etc… )

Add extra static routes
At this point, all internet traffic should go through the tunnel and any traffic to your internal network (NAS? etc… ) should still stay internal. This is, if you only have one subnet, which is the same as your OSMC box is sitting in.
If you however have multiple subnets (for example a different subnet for wired and for wireless) you will need to add an extra static route so that traffic for the other subnet is not sent down through the tunnel to be lost forever…
I did this by adding an ExecStartPost and ExecStopPost entry in the /etc/systemd/system/openpyn.service-file:

ExecStart=/usr/local/bin/openpyn be --silent
ExecStartPost=/sbin/ip route add 192.168.1.0/24 via 192.168.0.1 dev eth0
ExecStop=/usr/local/bin/openpyn --kill
ExecStopPost=/sbin/ip route del 192.168.1.0/24 via 192.168.0.1 dev eth0

Ofcourse:

  • change 192.168.1.0/24 into the required subnet,
  • 192.168.0.1 into your default gateway and
  • change eth0 into the interface your network is connected at.

Netflix
Now with Kodi 18, many may want to watch Netflix on Kodi. However Netflix actively tries to block VPN usage.

Netflix through VPN
Disclaimer: I don’t have a NordVPN netflix-compatible server in my country, so I can’t test this for myself. Also Netflix is actively trying to block all VPN usage, so even those “Netflix-compatible” servers may not work. And on top of that, according to this issue: Ca'nt connect with a VPN- AGAIN. · Issue #181 · CastagnaIT/plugin.video.netflix · GitHub it may even not work at all… But I include this section for completeness, let me know in the comments if you manage to get this working :slight_smile: :

NordVPN provides Netflix-compatible VPN servers to use. To select such a server using openpyn, you can add the option --netflix to the openpyn command in /etc/systemd/system/openpyn.service.
NordVPN however does not have those servers in every country. You can check this with:
openpyn -l <countrycode> --netflix.

Netflix bypassing VPN
If you don’t have such a server in your country, and you choose a server in another country, Netflix will think you are watching from within that country, and the content may be different.
If you don’t want that, or the netflix-compatible servers just don’t work, you can bypass the VPN for Netflix by adding static routes to your default gateway for all Netflix ip-ranges and additionally for all Amazon AWS ip ranges as Netflix is running many services in AWS.
As both have many ip-ranges, I made this script /usr/local/bin/bypass_vpn_static_routes.sh to automate this:

#!/bin/bash

gateway=192.168.0.1
interface=eth0

netflix_ranges=$(curl https://ipinfo.io/AS2906 | grep -e "^ *[0-9]\{2,3\}\.[0-9]\{2,3\}\.[0-9]\{2,3\}\.0/24" | tr -d " ")
aws_ranges=$(curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | grep ip_prefix | cut -d"\"" -f4 | sort -u)

case "$1" in
        start)
                # Routes to bypass VPN for Netflix ranges
                for range in $netflix_ranges; do
                        /sbin/ip route add $range via $gateway dev $interface
                done

                # Routes to bypass Amazon AWS ranges, required for Netflix
                for range in $aws_ranges; do
                        /sbin/ip route add $range via $gateway dev $interface
                done
                ;;
        stop)
                # Routes to bypass VPN for Netflix ranges
                for range in $netflix_ranges; do
                        /sbin/ip route del $range via $gateway dev $interface
                done

                # Routes to bypass Amazon AWS ranges, required for Netflix
                for range in $aws_ranges; do
                        /sbin/ip route del $range via $gateway dev $interface
                done
                ;;                                                        
esac

which I call from the ExecStartPost and ExecStopPost entry in the /etc/systemd/system/openpyn.service -file (you can also add your own static routes to this script instead of directly in the systemd unit-file):

ExecStart=/usr/local/bin/openpyn be --skip-dns-patch --p2p
ExecStartPost=/usr/local/bin/bypass_vpn_static_routes.sh start
ExecStop=/usr/local/bin/openpyn --kill
ExecStopPost=/usr/local/bin/bypass_vpn_static_routes.sh stop

This currently adds arround 1170 rules to bypass the VPN.
Be aware however, that we can’t determine which IP’s or ranges in AWS are actually used by Netflix (as this also constantly changes by the design of the AWS cloud services). As a result, any AWS cloud service will now bypass the VPN…

If anyone has a suggestion on how to improve this? Idea’s are temporarly disabling VPN when starting Netflix, or only adding those routes when starting Netflix and removing them again afterwards. But I don’t know how I would make kodi do this…

Check VPN status and logging
You can check the IP you are using now with curl ipinfo.io/ip, which should be different than the IP your ISP gave you.
The status of the VPN set up by openpyn can be checked using systemctl status openpyn and the openvpn logging can be found by running journalctl -u openpyn.

Updating VPN config-files
Once in a while you probably will need to update the NordVPN ovpn configfiles. This can be done with openpyn --update.
This could be added to a crontab, however crontab also is not installed by default on an OSMC. You are free to experiment with that :slight_smile:


EDIT 2019-12-18: Added disclaimer to ‘Netflix through VPN’-instructions
EDIT 2019-06-25: Added Netflix instructions
EDIT 2018-10-11: Added psmisc dependency and tip to check vpn status

6 Likes

Hey @ chojin

Thanks for your article!
I just tried to set up the vpn (NordVPN) on my Vero4k+, but somehow struggle to check if it actually worked.
How can I check if the VPN is actually up and running?

Btw, I’m so not Linux user! All I do is copy/paste into putty.
So, if there is a question for me to answer, keep that in mind please :slight_smile:

Hi,

curl ipinfo.io/ip.

Copy the above into your putty session, when the vero is connected to the VPN. It should be different from the public IP provided by your ISP.

Thanks Tom.

1 Like

Thanks for your reply.
It seems like it didn’t quite work out. Still have my normal ISP IP.
Any advice on how I can get the VPN running (ideally automatically on startup)?

With the output of systemctl status openpyn and/or journalctl -u openpyn, you should be able to determine if the service is running correctly. And if not, why:

The first few lines of the systemctl command output should be something like this:

openpyn.service - NordVPN connection manager
   Loaded: loaded (/etc/systemd/system/openpyn.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2018-10-02 22:21:02 CEST; 1 weeks 1 days ago

If it mentions “disabled” on the “Loaded:”-line, you should enable it with the command systemctl enable openpyn which means that systemd will try to start the service automatically during boot of the device.
If the “Active:”-line tells you that the service is stopped, you should try to start it manually with systemctl start openpyn. If it tells you that it failed however, you will have to dig in the logging which you will find by using the command journalctl -u openpyn

Alright, I checked and it said at “Active:” that it’s inactive.
Itried to activate it with systemctl enable openpyn and checked again.
Looks like it turns itself off immediately:

* openpyn.service - NordVPN connection manager
   Loaded: loaded (/etc/systemd/system/openpyn.service; enabled; vendor preset:
   Active: inactive (dead) since Thu 2018-10-11 12:06:54 CEST; 2s ago
  Process: 7282 ExecStop=/usr/local/bin/openpyn --kill (code=exited, status=0/SU
  Process: 7276 ExecStart=/usr/local/bin/openpyn --p2p --silent (code=exited, st
  Process: 7273 ExecStartPre=/bin/sleep 5 (code=exited, status=0/SUCCESS)
 Main PID: 7276 (code=exited, status=0/SUCCESS)

Oct 11 12:06:52 osmc systemd[1]: Started NordVPN connection manager.
Oct 11 12:06:54 osmc openpyn[7282]: 2018-10-11 12:06:54 [WARNING] Killing the ru
Oct 11 12:06:54 osmc openpyn[7282]: Killing the running processes
Oct 11 12:06:54 osmc sudo[7285]:     root : TTY=unknown ; PWD=/usr/local/lib/pyt
Oct 11 12:06:54 osmc sudo[7285]: pam_unix(sudo:session): session opened for user
Oct 11 12:06:54 osmc sudo[7285]: pam_unix(sudo:session): session closed for user
Oct 11 12:06:54 osmc sudo[7303]:     root : TTY=unknown ; PWD=/usr/local/lib/pyt
Oct 11 12:06:54 osmc sudo[7303]: pam_unix(sudo:session): session opened for user
Oct 11 12:06:54 osmc sudo[7303]: pam_unix(sudo:session): session closed for user
Oct 11 12:06:54 osmc openpyn[7282]: sudo: killall: command not found

Not quite sure how to go from here…

Looks like openpyn is looking for killall:

sudo apt-get install psmisc

Thanks Tom.

1 Like

Awesome, we’re closer :slight_smile:
Thank you so much for your help lads!

 * openpyn.service - NordVPN connection manager
   Loaded: loaded (/etc/systemd/system/openpyn.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-10-11 19:04:48 CEST; 52s ago
  Process: 1004 ExecStartPre=/bin/sleep 5 (code=exited, status=0/SUCCESS)
 Main PID: 1162 (openpyn)
   CGroup: /system.slice/openpyn.service
           |-1162 /usr/bin/python3 /usr/local/bin/openpyn uk
           |-1891 /usr/bin/python3 /usr/local/bin/openpyn-management
           |-1908 sudo openvpn --redirect-gateway --auth-retry nointeract --config /usr/local/lib/python3.5/dist-packages/openpyn/files/ovpn_udp/uk287.nordvpn.com.udp.ovpn --auth-user-pass /usr/local/lib/python3.5/dist-packages/openpyn/c
           `-1915 openvpn --redirect-gateway --auth-retry nointeract --config /usr/local/lib/python3.5/dist-packages/openpyn/files/ovpn_udp/uk287.nordvpn.com.udp.ovpn --auth-user-pass /usr/local/lib/python3.5/dist-packages/openpyn/creden

Oct 11 19:05:27 osmc openpyn[1162]: Thu Oct 11 19:05:27 2018 Validating certificate extended key usage
Oct 11 19:05:27 osmc openpyn[1162]: Thu Oct 11 19:05:27 2018 ++ Certificate has EKU (str) TLS Web Server Authentication, expects TLS Web Server Authentication
Oct 11 19:05:27 osmc openpyn[1162]: Thu Oct 11 19:05:27 2018 VERIFY EKU OK
Oct 11 19:05:27 osmc openpyn[1162]: Thu Oct 11 19:05:27 2018 VERIFY OK: depth=0, C=PA, ST=PA, L=Panama, O=NordVPN, OU=NordVPN, CN=uk287.nordvpn.com, name=NordVPN, emailAddress=cert@nordvpn.com
Oct 11 19:05:30 osmc openpyn[1162]: Thu Oct 11 19:05:30 2018 Control Channel: TLSv1.2, cipher TLSv1/SSLv3 ECDHE-RSA-AES256-GCM-SHA384, 2048 bit RSA
Oct 11 19:05:30 osmc openpyn[1162]: Thu Oct 11 19:05:30 2018 [uk287.nordvpn.com] Peer Connection Initiated with [AF_INET]89.238.139.77:1194
Oct 11 19:05:31 osmc openpyn[1162]: Thu Oct 11 19:05:31 2018 SENT CONTROL [uk287.nordvpn.com]: 'PUSH_REQUEST' (status=1)
Oct 11 19:05:31 osmc openpyn[1162]: Thu Oct 11 19:05:31 2018 AUTH: Received control message: AUTH_FAILED
Oct 11 19:05:31 osmc openpyn[1162]: Thu Oct 11 19:05:31 2018 SIGUSR1[soft,auth-failure] received, process restarting
Oct 11 19:05:31 osmc openpyn[1162]: Thu Oct 11 19:05:31 2018 Restart pause, 10 second(s)

I tried now to check with curl ipinfo.io/ip, but still get my normal ISP IP which confuses me.
Maybe I missed some settings (maybe at NordVPN directly).
I will check in that direction.

My bad :man_facepalming:
Got it now.

Thanks again for your amazing support (and patience)!

1 Like

What was it? Will help other users avoid the same mistake.

Thanks Tom.

AUTH: Received control message: AUTH_FAILED
Username/password combination simply was wrong :smile:

Now I have the issue that none of my streaming plug-ins care to open anymore but just keep loading, but I don’t want to mix topics here.

1 Like

Added psmisc to the dependencies to install. Thanks!

1 Like

Added curl ipinfo.io/ip as a tip to check the vpn status. Thanks!

1 Like

Hey @ Chojin,

Thanks for your article. I just tried to set up and I assume it looks fine.
However, I have an additional question. I am located in NL but the script connect to a uk server. I probably have to change it to NL but don’t know where to change it.
I made a change in openpyn.service but still connect to a uk server.
ExecStart=/usr/local/bin/openpyn nl --p2p --skip-dns-patch --silent

Can you help me out?
Many thanks in advance.
Mark

HI,

Looks like that should work, you could try:

ExecStart=/usr/local/bin/openpyn --country-code nl --p2p --skip-dns-patch --silent

Thanks Tom.

Hi,

Just wondering, does this work smoothly with Kodi 18 as well?

Thanks,

Version of Kodi should have no bearing on this function.

1 Like

I added instructions to this How-to on how to use Netflix in combination with the VPN.

See [HOW-TO ALL PLATFORMS]Can I use Netflix on OSMC?(post 4) - #4 by joakim_s for instructions on how to set up the Netflix plugin itself.

Hey chojin,

Thanks for your tutos here, it has been a great help for a beginner with OSMC like me!
I’ve been trying to bypass NordVPN using your script (with my own gateway address):

Unfortunately it doesn’t seem working for me:

  • without VPN, I can use Netflix without problem
  • with VPN active and without running script, I get 420 errors (normal behaviour)
  • with VPN active + running the script, I get timeouts and again 420 errors:
2019-08-05 15:13:56.632 T:1915893296  NOTICE: VideoPlayer::OpenFile: plugin://plugin.video.netflix/play/show/80991872/season/80992410/episode/81014282/
2019-08-05 15:13:56.633 T:1477440224  NOTICE: Creating InputStream
2019-08-05 15:14:27.693 T:1477440224   ERROR: CCurlFile::FillBuffer - Failed: Timeout was reached(28)
2019-08-05 15:14:27.693 T:1477440224   ERROR: CCurlFile::Open failed with code 0 for http://23.246.50.151/?o=AQNM5nMgbPRA5tv-I6C5LPJQrCMIRnPYoBU9jwZruQ2RmrM9zJApp_8vWJmjKk9CT4O7SoL0fRydnk9TKYPNNp25QbIAjpDo5GgxI8k1iefOBUFmDjQcPAjxfx6e9bPoghOCTDBl9qSYVF2d6WlbpEUa2BTOcLo&v=5&e=1565054037&t=4QbiM2dVj5pi8B1T7ecdLkfR2dY:
2019-08-05 15:14:27.693 T:1477440224   ERROR: AddOnLog: InputStream Adaptive: No MOOV in stream!
2019-08-05 15:14:57.711 T:1763701472   ERROR: CCurlFile::FillBuffer - Failed: Timeout was reached(28)
2019-08-05 15:14:57.711 T:1763701472   ERROR: CCurlFile::Open failed with code 0 for http://23.246.50.151/?o=AQNM5nMgbPRA5tv-I6C5LPJQrCMIRnPYoBU9jwZruQ2RmrM9zJApp_8vWJmjKk9CT4O7SoL0fRydnk9TKYPNNp25QbIAjpDo5GgxI8k1iefOBUFmDjQcPAjxfx6e9bPoghOCTDBl9qSYVF2d6WlbpEUa2BTOcLo&v=5&e=1565054037&t=4QbiM2dVj5pi8B1T7ecdLkfR2dY:
2019-08-05 15:14:57.715 T:1477440224   ERROR: CVideoPlayer::OpenInputStream - error opening [plugin://plugin.video.netflix/play/show/80991872/season/80992410/episode/81014282/]
2019-08-05 15:14:57.715 T:1477440224  NOTICE: CVideoPlayer::OnExit()
2019-08-05 15:14:57.778 T:1915893296  NOTICE: CVideoPlayer::CloseFile()
2019-08-05 15:14:57.778 T:1915893296  NOTICE: VideoPlayer: waiting for threads to exit
2019-08-05 15:14:57.778 T:1915893296  NOTICE: VideoPlayer: finished waiting
2019-08-05 15:17:01.932 T:1915893296  NOTICE: VideoPlayer::OpenFile: plugin://plugin.video.netflix/play/show/80991872/season/80992410/episode/81014283/
2019-08-05 15:17:01.934 T:1469047520  NOTICE: Creating InputStream
2019-08-05 15:17:03.069 T:1469047520   ERROR: AddOnLog: InputStream Adaptive: Download http://151.99.109.229/?o=AQMvAHmJaS6HoP7G2GSzGZ_TPL-OPou-ExuQ6khhf778_9vufhSbjDz5E9romrosl7Y1MB8lj2r7iwsYUVI3X-A5teJK4akO2jhm83wykjRhChaaaLn7Yv5x9AYD63Z2CGLHqbGN7_EFyHXkvphLuGTJJQzLGg&v=5&e=1565054222&t=_82i2nYfm7brywn1XCdbeWyfx6I failed with error: 420
2019-08-05 15:17:03.070 T:1469047520   ERROR: AddOnLog: InputStream Adaptive: No MOOV in stream!
2019-08-05 15:17:03.108 T:1755308768   ERROR: AddOnLog: InputStream Adaptive: Download http://151.99.109.229/?o=AQMvAHmJaS6HoP7G2GSzGZ_TPL-OPou-ExuQ6khhf778_9vufhSbjDz5E9romrosl7Y1MB8lj2r7iwsYUVI3X-A5teJK4akO2jhm83wykjRhChaaaLn7Yv5x9AYD63Z2CGLHqbGN7_EFyHXkvphLuGTJJQzLGg&v=5&e=1565054222&t=_82i2nYfm7brywn1XCdbeWyfx6I failed with error: 420
2019-08-05 15:17:03.111 T:1469047520   ERROR: CVideoPlayer::OpenInputStream - error opening [plugin://plugin.video.netflix/play/show/80991872/season/80992410/episode/81014283/]
2019-08-05 15:17:03.111 T:1469047520  NOTICE: CVideoPlayer::OnExit()
2019-08-05 15:17:03.253 T:1915893296  NOTICE: CVideoPlayer::CloseFile()
2019-08-05 15:17:03.253 T:1915893296  NOTICE: VideoPlayer: waiting for threads to exit
2019-08-05 15:17:03.253 T:1915893296  NOTICE: VideoPlayer: finished waiting

Would you have any advice to troubleshout this?

I must precise that I don’t use the --skip-dns-patch option when launching Openpyn service.

I may have a hint: once I run the script, I cannot access anymore the JSON on amazonaws.com in order to clean the static routes. Maybe I should check if the routes are properly configured but I don’t know how to do it.

Thanks!

You should be able to check current active routes using the ip route command.

Can you still nslookup amazonaws.com ? and ping ?