Nordvpn wireguard split tunnel namespace SOLVED

So i have spent a good few days getting to the bottom of this, but i have managed to use a manual wireguard configuration for Nordvpn (nordlynx) and a namespace setup so that all traffic uses my clearnet eth0 interface via my isp address, but assigned a namespace (vpnns) to use the nordlynx connection under the interface wg0

until recently, i simply used the nordvpn app but set it to ‘routing disabled’ which used to leave all my traffic rules as standard, in that traffic wnet via eth0, but i could add some uid based routing to send all traffic via nordlynx interface (so just execute a command as the configured user to use vpn), but this has recently stopped working so i have had to find another approach.

you need wireguard installed (obvs)

The first challenge is to get the nordvpn config details, but there are a couple of really useful blog posts out there, in particular this

NordLynx (WireGuard NordVPN implementation) (opnsense.org)

based on that information you should then create a wg0.conf file (in /etc/wireguard)
this file should look like this

[Interface]
PrivateKey = [your private key]
ListenPort = 51820
Address = 10.5.0.2
DNS = 103.86.96.100, 103.86.99.100

[Peer]
PublicKey = [public key of specific server obtained from the step above]
AllowedIPs = 0.0.0.0/0
Endpoint = [address from step above]:51820
PersistentKeepalive = 25

once you have that, you can test that it works by executing

sudo wg-quick up /etc/wireguard/wg0.conf
then

curl ifconfig.me

you should get the exit ip of your vpn, not your isp address

if you just want all your traffic through the vpn, you are finished (albeit you could add some startup scripts to launch it on boot)

but i want to create an effective split tunnel, which i will achieve by creating a namespace called vpnns with eth0 as the default route for the main namespace, and wg0 as the default route for vpnns

so this script

#!/bin/bash

# Start WireGuard
sudo wg-quick up /etc/wireguard/wg0.conf

# Remove IP rule
sudo ip rule del not fwmark 51820 table 51820

# Create network namespace
sudo ip netns add vpnns

# Move wg0 interface to the network namespace
sudo ip link set wg0 netns vpnns

# Add IP address to wg0 interface within the namespace
sudo ip netns exec vpnns ip addr add 10.5.0.2/32 dev wg0

# Bring up wg0 interface within the namespace
sudo ip netns exec vpnns ip link set wg0 up

# Add default route via eth0
sudo ip route add default via 192.168.0.1 dev eth0

# Add default route via wg0 within the namespace
sudo ip netns exec vpnns ip route add default dev wg0

# Test external connectivity within the namespace
sudo ip netns exec vpnns curl ifconfig.me

you need to make this script executable (chmod +x)

(obviously the curl command is unnecessary for the startup process, but useful as confirmation that the script worked if run manually via terminal)

if you want this to run at startup pop it in /etc/init.d and create the following symlinks

sudo ln -s /etc/init.d/wireguard.sh /etc/rc2.d/S99wireguard
sudo ln -s /etc/init.d/wireguard.sh /etc/rc3.d/S99wireguard
sudo ln -s /etc/init.d/wireguard.sh /etc/rc4.d/S99wireguard
sudo ln -s /etc/init.d/wireguard.sh /etc/rc5.d/S99wireguard

now when my server boots, my main namespace continues to ues eth0 but if i run

sudo ip netns exec vpnns

it will execute through my nordlynx wireguard interface

specifically i use this for geo-location circumvention with yt-dlp, but once you have these namespaces set up, you can configure a whole variety of split tunnel goodness

1 Like

for the sake of ease, here is a text file with all of the nord wireguard server addresses with their corresponding public key
wireguardaddresses.txt (37.7 KB)

ok, so apologies for constantly posting to myself, but here is a self contained script that does the whole thing for me.

you will need wireguard and a few basic modules installed (curl, awk, jq)
you will also need to obtain your nordvpn private key. the way to do that is described here Getting NordVPN WireGuard details · GitHub but basically you start a nordlynx connection using the official nordvpn app and then run sudo wg show nordlynx private-key

replace with your private key in this section

[Interface]
PrivateKey =
ListenPort = 51820
Address = 10.5.0.2
DNS = 103.86.96.100, 103.86.99.100

this script will then look up the list of available countries currently running nord servers and prompt you to select one
once a country is selected, the script will choose the recommended server in that country that offers wireguard
it will then create a config file for that server and launch a wireguard connection
it then creates a namespace called vpnns and moves the wireguard connection into that namespace, before creating rules to route all traffic to eth0 except traffic from the vpnns namespace which goes through the connection

#!/bin/bash

######### Prerequisites
### main route via 192.168.0.1 on eth0
### wireguard, jq, curl, awk 
## you will need your nordvpn private key
## your private key is most easily obtained by running  #sudo wg show nordlynx private-key# while connected to the nordvpn app using nordlynx technology 

# Check if the private key placeholder is present in the script
if [[ $(grep -c "PrivateKey = <YOUR PRIVATE KEY>" "$0") -ge 2 ]]; then
    echo "The private key has not been replaced. Please replace <YOUR PRIVATE KEY> with your actual private key. your private key is most easily obtained by running  #sudo wg show nordlynx private-key# while connected to the nordvpn app using nordlynx technology"
    exit 1
fi

# Curl command to get the country list
country_list=$(curl --silent "https://api.nordvpn.com/v1/servers/countries" | jq --raw-output '.[] | [.id, .name] | @tsv')

# Convert the country list to an array
countries=()
while IFS=$'\t' read -r code country; do
    countries+=("$country")
done <<< "$country_list"

# Display the country options
echo "To which country would you like to connect:"
for ((i=0; i<${#countries[@]}; i++)); do
    echo "$(($i+1)). ${countries[$i]}"
done

# Prompt the user for their choice
read -p "Enter the number corresponding to your choice: " choice

# Validate the user's input
if [[ ! $choice =~ ^[1-9][0-9]*$ ]] || (( choice < 1 || choice > ${#countries[@]} )); then
    echo "Invalid choice. Exiting."
    exit 1
fi

# Get the selected country code
selected_country_code=$(echo "$country_list" | awk -v choice="$choice" '{ if (NR == choice) print $1 }')

# Formulate and execute the curl command to get server recommendations
output=$(curl --silent "https://api.nordvpn.com/v1/servers/recommendations?filters\[country_id\]=$selected_country_code&filters\[servers_technologies\]\[identifier\]=wireguard_udp")

# Extract the desired fields using jq
server_hostname=$(echo "$output" | jq -r '.[0].hostname')
station=$(echo "$output" | jq -r '.[0].station')
public_key=$(echo "$output" | jq -r '.[0].technologies[] | select(.identifier == "wireguard_udp") | .metadata[] | select(.name == "public_key") | .value')

# Create the wireguard conf file
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
PrivateKey = <YOUR PRIVATE KEY>
ListenPort = 51820
Address = 10.5.0.2
DNS = 103.86.96.100, 103.86.99.100

[Peer]
PublicKey = $public_key
AllowedIPs = 0.0.0.0/0
Endpoint = $station:51820
PersistentKeepalive = 25


#$server_hostname
EOF

sudo ip netns exec vpnns ip route del default dev wg0
sudo ip netns exec vpnns ip link set wg0 down
sudo ip netns exec vpnns ip addr del 10.5.0.2/32 dev wg0
sudo ip netns del vpnns
sudo wg-quick down /etc/wireguard/wg0.conf

# Start WireGuard
sudo wg-quick up /etc/wireguard/wg0.conf

# Remove IP rule
sudo ip rule del not fwmark 51820 table 51820

# Create network namespace
sudo ip netns add vpnns

# Move wg0 interface to the network namespace
sudo ip link set wg0 netns vpnns

# Add IP address to wg0 interface within the namespace
sudo ip netns exec vpnns ip addr add 10.5.0.2/32 dev wg0

# Bring up wg0 interface within the namespace
sudo ip netns exec vpnns ip link set wg0 up

# Add default route via eth0
sudo ip route add default via 192.168.0.1 dev eth0

# Add default route via wg0 within the namespace
sudo ip netns exec vpnns ip route add default dev wg0

# Test external connectivity within the namespace
sudo ip netns exec vpnns curl ifconfig.me