How to use NordVPN in a LXD container

NordVPN is one of many VPN services. I was asked to have a look at how to make it work in a LXD container and as a result I am writing this post. I am not advertising this service, nor do I use affiliate links, etc. Up to now, NordVPN have refused to fix their official Linux client to work in a container.

Installing the official client

Let’s install the official client in a LXD container. Create a container and get a shell into it. Then, download the Deb package and install it. The initial Deb package is really small. It just has instructions to setup the NordVPN repository to your system. After you install this package, you apt update to refresh the package list and then you can install the actual nordvpn package.

$ lxc launch ubuntu:18.04 nordvpn
Creating nordvpn
Starting nordvpn
$ lxc ubuntu nordvpn
ubuntu@nordvpn:~$ wget https://repo.nordvpn.com/deb/nordvpn/debian/pool/main/nordvpn-release_1.0.0_all.deb
ubuntu@nordvpn:~$ sudo apt install -f ./nordvpn-release_1.0.0_all.deb
...
ubuntu@nordvpn:~$ sudo apt update
...
ubuntu@nordvpn:~$ sudo apt install -y nordvpn
...
NordVPN for Linux successfully installed!
To get started, type 'nordvpn login' and enter your NordVPN account details. Then type 'nordvpn connect' and you’re all set! If you need help using the app, use the command 'nordvpn --help'.
...
ubuntu@nordvpn:~$ nordvpn
Welcome to NordVPN Linux client app!
Version 3.7.3
Website: https://nordvpn.com
Usage: nordvpn [global options] command [command options] [arguments…]
... 
ubuntu@nordvpn:~$

Running the official NordVPN client

Let’s attempt to run the official NordVPN client. We log in, and then we connect. Does not work! Something is wrong.

ubuntu@nordvpn:~$ nordvpn login --username myusername@example.com --password mypassword
Welcome to NordVPN! You can now connect to VPN by using 'nordvpn connect'.
ubuntu@nordvpn:~$ nordvpn connect
Connecting to Germany #500 (de500.nordvpn.com)
transport is closing
ubuntu@nordvpn:~$ nordvpn connect
Whoops! Cannot reach System Daemon.
ubuntu@nordvpn:~$

We look into /var/log/syslog. Here are the offending lines. The official client crashes due to some array bounds error.

Jun 16 19:59:31 nordvpn nordvpnd[1423]: debug: Tue Jun 16 19:59:31 2020 MANAGEMENT: Connected to management server at /var/run/nordvpn-openvpn.sock
Jun 16 19:59:31 nordvpn nordvpnd[1423]: 2020/06/16 19:59:31 [INFO] Tue Jun 16 19:59:31 2020 MANAGEMENT: Connected to management server at /var/run/nordvpn-openvpn.sock
Jun 16 19:59:31 nordvpn nordvpnd[1423]: panic: runtime error: index out of range [1] with length 1
Jun 16 19:59:31 nordvpn nordvpnd[1423]: goroutine 117 [running]:
Jun 16 19:59:31 nordvpn nordvpnd[1423]: nordvpn/daemon.ruleParsing(…)
Jun 16 19:59:31 nordvpn nordvpnd[1423]: #011/builds/nordvpn/apps-source/linux-app/src/daemon/vpn_ipv6.go:117
Jun 16 19:59:31 nordvpn nordvpnd[1423]: nordvpn/daemon.(Ipv6).Disable(0xc000390844, 0x0, 0x0) Jun 16 19:59:31 nordvpn nordvpnd[1423]: #011/builds/nordvpn/apps-source/linux-app/src/daemon/vpn_ipv6.go:43 +0x6c7 Jun 16 19:59:31 nordvpn nordvpnd[1423]: nordvpn/daemon.(OpenVPN).Start(0xc0004466e0, 0x2b89520, 0xc00042dec0, 0x18, 0xc00042dee0, 0x18, 0x0, 0x0, 0x0, 0x0, …)
Jun 16 19:59:31 nordvpn nordvpnd[1423]: #011/builds/nordvpn/apps-source/linux-app/src/daemon/vpn_openvpn.go:159 +0xd11
Jun 16 19:59:31 nordvpn nordvpnd[1423]: created by nordvpn/daemon.Connect
Jun 16 19:59:31 nordvpn nordvpnd[1423]: #011/builds/nordvpn/apps-source/linux-app/src/daemon/rpc.go:288 +0x882
Jun 16 19:59:31 nordvpn systemd[1]: nordvpnd.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Jun 16 19:59:31 nordvpn systemd[1]: nordvpnd.service: Failed with result 'exit-code'.
Jun 16 19:59:36 nordvpn systemd[1]: nordvpnd.service: Service hold-off time over, scheduling restart.

The same error appears whether you run the client with sudo -H, whether you run it in a privileged container. Something is wrong in this official NordVPN client.

So, what do we do now? Apparently, their client is based on OpenVPN, therefore let’s use the OpenVPN client directly.

Using the OpenVPN client

We exit from the container, remove it and create a new one. One without the official client.

ubuntu@nordvpn:~$ logout
$ lxc stop nordvpn
$ lxc delete nordvpn
$ lxc launch ubuntu:18.04 nordvpn
Creating nordvpn
Starting nordvpn
$ lxc ubuntu nordvpn
ubuntu@nordvpn:~$

We then update the package list and install the openvpn package.

ubuntu@nordvpn:~$ sudo apt update
ubuntu@nordvpn:~$ sudo apt install -y openvpn

OpenVPN requires configuration files for the VPN servers. NordVPN has this list online at https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip Let’s download it. It’s a 21MB file.

ubuntu@nordvpn:~$ wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip

We unzip into the /etc/openvpn/client directory. The ZIP has folders, so we instruct unzip to ignore folders and dump them all in the given folder.

ubuntu@nordvpn:~$ sudo unzip -d /etc/openvpn/client/ -j ovpn.zip

We are ready to connect to some VPN server. But which one? We can select any. This page, https://nordvpn.com/servers/tools/, will auto-detect the closest VPN server. Let’s assume the result is de505.nordvpn.com. We do not connect yet. Do the following section to avoid DNS leakage, then we connect on the next section.

Avoiding DNS leakage

By default, OpenVPN does not set the DNS server and keeps the existing DNS configuration. The result of this, is DNS leakage; that is, name resolutions do not happen through the VPN but use the local network.

What needs to happen, is to add the appropriate script to OpenVPN to configure the DNS when the VPN is established, and when the VPN is teared down.

We use Ubuntu 18.04 LTS in the container, therefore, we configure systemd-resolved for this. Here are the commands. We install the helper, and edit the .ovpn file to use the helper.

ubuntu@nordvpn:~$ sudo apt install openvpn-systemd-resolved

Then, edit the OpenVPN configuration file, in our case, /etc/openvpn/client/de505.nordvpn.com.tcp.ovpn and add the following lines,

script-security 2
up /etc/openvpn/update-systemd-resolved
down /etc/openvpn/update-systemd-resolved
down-pre

We are ready now to connect. Note that if you change server, you need to edit the corresponding file manually as above.

Making the connection

We are ready to make the connection.

ubuntu@nordvpn:~$ sudo openvpn /etc/openvpn/client/de505.nordvpn.com.tcp.ovpn
Tue Jun 16 21:17:17 2020 OpenVPN 2.4.4 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on May 14 2019
Tue Jun 16 21:17:17 2020 library versions: OpenSSL 1.1.1 11 Sep 2018, LZO 2.08
Enter Auth Username: myusername@example.com
Enter Auth Password: ***********
...
<14>Jun 16 21:17:42 update-systemd-resolved: Adding DNS Routed Domain .
<14>Jun 16 21:17:42 update-systemd-resolved: Adding IPv4 DNS Server 103.86.96.100
<14>Jun 16 21:17:42 update-systemd-resolved: Adding IPv4 DNS Server 103.86.99.100
...
Tue Jun 16 21:17:42 2020 Initialization Sequence Completed

Looks good. The VPN circuit is active until you hit Ctrl+C here to interrupt OpenVPN. You need to open a new terminal to the LXD container to use the VPN. We can see that the proper new DNS entries have been added to systemd-resolved.

$ lxc ubuntu nordvpm
ubuntu@nordvpn:~$ systemd-resolve --status
...
Link 7 (tun0)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 103.86.96.100
                      103.86.99.100
          DNS Domain: ~.
ubuntu@nordvpn:~$

Conclusion

The official NordVPN client does not work in a LXD container, and it appears that it’s just a bug that they know about and do not intend to fix. The developers did not envision the client to run in a container, nor did they test it. We work around this issue by installing the OpenVPN client and using it to connect to one of their VPN servers.

Permanent link to this article: https://blog.simos.info/how-to-use-nordvpn-in-a-lxd-container/

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: