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!