fredrik.lanker.se

WireGuard VPN in a network namespace

2024-08-22

The scenario

Say you want to run only a specific program via a VPN, but let the rest of your system use the ordinary connection. For our example, we will use curl as the program that should use the VPN tunnel, and as VPN provider, we will use Mullvad and their WireGuard endpoints, but the setup should work for any VPN provider using WireGuard.

Before we start

To verify if we are connected via Mullvad or not, we can make calls to https://am.i.mullvad.net/connected.

Let's see how it looks before we start:

$ curl https://am.i.mullvad.net/connected
You are not connected to Mullvad. Your IP address is 111.222.111.111

Great, just as expected we are not using the VPN tunnel.

For setting everything up, we will use the wg tool, part of the wireguard-tools package. See https://www.wireguard.com/install/ for installation instructions. We will also need a config file, this can be generated on the Mullvad page and will look something like:

[Interface]
PrivateKey = <private key>
Address = <IPv4>/32,<IPv6>/128

[Peer]
PublicKey = <public key>
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = <IP of the server>:51820

Where <ip of the server> is the IP address of the server you want to use, which can also be found in the list of servers on Mullvad's site. You will probably have some additional fields in your config.

The setup

We'll start by creating a new network namespace, aptly named vpn:

# ip netns add vpn

Then we roughly follow the steps from https://www.wireguard.com/quickstart/#command-line-interface:

Add a new wireguard interface:

# ip link add wg0 type wireguard

Move the device to our vpn namespace:

# ip link set wg0 netns vpn

From now on we will use ip -n vpn to run the command in the vpn namespace. -n is short for netns exec ip, i.e., the command will be run in the provided namespace.

Set IP address for the interface. The IP is found in the Interface.Address field in the config file, we'll use the v4 address.

# ip -n vpn addr add <IP>/32 dev wg0

Use wg to set keys and endpoints specified in the config file:

# ip netns exec vpn wg setconf wg0 <config file>

Activate the interface by setting it to UP.

# ip -n vpn link set wg0 up

Make our interface the default route:

# ip -n vpn route add default dev wg0

Usage

We now have a network namespace named vpn that will route traffic via your VPN provider using WireGuard. To use it, prefix commands with ip netns vpn exec <command>. To verify that everything works, we run curl in the same way as before we started, but this time we run it in our network namespace:

# ip netns exec vpn curl https://am.i.mullvad.net/connected
You are connected to Mullvad (server gr-ath-wg-101). Your IP address is 132.133.134.134

And just to make sure, we'll also check that the result of running it outside of the vpn namespace hasn't changed:

$ curl https://am.i.mullvad.net/connected
You are not connected to Mullvad. Your IP address is 111.222.111.111

Success!

feed github mastodon listenbrainz matrix