How to Route Your Home-VPN to Mullvad for Accessibility and Privacy

I wanted to achieve the ability to use Mullvad as my go-to VPN service while also accessing my home services, like PiHole and Audiobookshelf, when I'm on the go. In this post, I'll walk you through the setup, as it requires some special settings to get the routing right.

I'm far away from being a network professional and iptables is breaking my brain sometimes as i'm still learning. To get this done I was searching through a lot of reddit posts, and other websites and getting help of some LLMs: reading and trying the settings and rules. It was very complicated first (for me), but I'd like to show y'all exactly my setup.

My Server

  • a VM running Debian bookworm
  • a WireGuard server is installed on that VM, which is accessible from the internet to connect to my home network via PiVPN.
  • Pi-hole is running on the same machine and is used for DNS (via dnscrypt-proxy)
  • a working WireGuard profile on my phone which uses Pi-hole for DNS
  • different services on other VMs like AudioBookShelf

What I want to add

  • a new WireGuard connection to mullvad which is used for Internet things, while still having access to my local services.

Let's start

Okay, so as we already have WireGuard installed on the VM (it acts as a server and a client if you want to) we first need to create a WireGuard config file for Mullvad. To do this you can just use the online config creator of Mullvad:

  • Login to Mullvad with your user ID
  • check into the Downloads Section and select WireGuard Configuration
  • select Linux as your platform and generate a new key
  • now select all the options you want, such as the desired endpoint and other preferred settings, and download the generated .conf file

Once the conf file is downloaded, I rename it to mullvad.conf and transfer it to my VM into /etc/wireguard/ (as root, via SFTP or any other method, or by copy-pasting it's content via SSH). I rename it to mullvad.conf because that will be the name of the network adapter, and we’ll need that name for our configuration edits.

Inside /etc/wireguard there is (in my case) also the wg0.conf which is the configuration of the WireGuard server to my home-network. We start editing here.

Edit your Home-VPN's config

Let's start and begin to edit my Home-VPN's config which is (in my case) wg0.conf (as root)

nano /etc/wireguard/wg0.conf

to something like this:

[Interface]
PrivateKey = XXXXXXXXXXXXXX
Address = 10.10.10.1/24
MTU = 1420
ListenPort = yourVPNPort

FwMark = 51820

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT;
PostUp = ip6tables -A FORWARD -i wg0 -j ACCEPT;
PostUp = iptables -t nat -A POSTROUTING -o mullvad -j MASQUERADE;
PostUp = ip6tables -t nat -A POSTROUTING -o mullvad -j MASQUERADE

PostDown = iptables -D FORWARD -i wg0 -j ACCEPT;
PostDown = ip6tables -D FORWARD -i wg0 -j ACCEPT;
PostDown = iptables -t nat -D POSTROUTING -o mullvad -j MASQUERADE;
PostDown = ip6tables -t nat -D POSTROUTING -o mullvad -j MASQUERADE


### my clients ###
[Peer]
PublicKey = XXXXXXXX
PresharedKey = XXXXXXXX
AllowedIPs = 10.10.10.2/32
⚠️
The IP's may differ in your case because these are picked by me personally. Just let these untouched like the Private and Public Keys
FwMark = 51820

FwMark is used to mark the data-packets in order to route them later to mullvad.

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT;
PostUp = ip6tables -A FORWARD -i wg0 -j ACCEPT;
PostUp = iptables -t nat -A POSTROUTING -o mullvad -j MASQUERADE;
PostUp = ip6tables -t nat -A POSTROUTING -o mullvad -j MASQUERADE

These are the firewall rules needed to forward the traffic from wg0 to mullvad and masquerade the sources IP address with Mullvad's.

Now Mullvad's .conf file

Let's edit mullvad.conf as well to something like this:

[Interface]
# Device: DeviceName
PrivateKey = XXXXXXXXXX
Address = SomeMullvadIP
DNS = SomeMullvadIP

FwMark = 51820

PostUp = ip rule add from 10.5.5.4 table main;
PostUp = iptables -t mangle -A PREROUTING -i eth0 -j CONNMARK --set-mark 51820;
PostUp = iptables -t mangle -A PREROUTING -m connmark --mark 51820 -j MARK --set-mark 51820

PreDown = ip rule del from 10.5.5.4 table main;
PreDown = iptables -t mangle -D PREROUTING -i eth0 -j CONNMARK --set-mark 51820;
PreDown = iptables -t mangle -D PREROUTING -m connmark --mark 51820 -j MARK --set-mark 51820

[Peer]
PublicKey = XXXXXXXXXXX
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = SomeMullvadIP:Port

By marking and tagging traffic (using the 51280 mark), we're controlling how specific types of traffic are handled. For example, in our VPN setup, certain types of traffic might need to be sent through Mullvad, while other traffic goes through your regular network adapter. These lines are enabling local communication via UDP and TCP.

10.5.5.4 is the local IP address of my VM, so you need to change it to your machine's IP.

The FwMark value needs to be the same as we have used in the other config.

eth0is my default network adapter which uses my LAN IP address, change its name to yours if it differs.

Test it

Now I restart the WireGuard-server and bring up the mullvad connection:

wg-quick up mullvad

and connect to my Home-VPN with my phone.

If everything works like on my end, you should be able to communicate with your local services, and when you check your IP (browserleaks for example) you should see the IP of the mullvad endpoint you picked before on your device.

Ressources:

Comments