EdgeOS setup with Mullvad VPN
January 10, 2022
Mullvad truly cares about the security and privacy of its users, and they have made all their VPN clients available as open source, so they are definitely my VPN provider of choice. Other than a unique 16-digit account number created during sign-up, no identifying information is required to use them.
Previously I have only used Mullvad on my laptop and mobile phone, but I wanted to extend the usage to most of my devices, including IoT devices that don't have a VPN client built-in. This protects me better against data profiling and allows the devices to bypass geoblocking at the same time.
I use a Ubiquiti EdgeRouter Lite on my home network, which has two LAN ports. I configured one of the LAN ports (eth2) to forward all the traffic through a VPN tunnel to Mullvad, while the other LAN port (eth1) continues to route the traffic normally. Here is how I configured this:
1. Download a VPN configuration file from Mullvad
Unfortunately, Wireguard support is not included in EdgeOS, so I had to download a configuration file for OpenVPN instead. In the example below, I make use of the ca-mtr (Montreal, Canada) profile.
In the configuration file provided by Mullvad, the client will pull routes, including a default route, which causes all traffic to go through the VPN interface. Normally you would want this, but as I only wanted to redirect the traffic from one of the LAN interfaces, I had to make a small change to the OpenVPN configuration file. We also don't want resolv.conf to be updated with Mullvad's DNS server because eth1 and the router itself should continue to use the ISP's DNS server (instead, Mullvad's DNS server will be configured as a DHCP option on eth2 in the next step).
mullvad_ca_mtr.conf should look like this:
up /etc/openvpn/update-resolv-conf down /etc/openvpn/update-resolv-conf
remote ca-mtr-104.mullvad.net 1300
remote ca-mtr-102.mullvad.net 1300
remote ca-mtr-107.mullvad.net 1300
remote ca-mtr-101.mullvad.net 1300
remote ca-mtr-103.mullvad.net 1300
remote ca-mtr-106.mullvad.net 1300
remote ca-mtr-105.mullvad.net 1300
remote ca-mtr-108.mullvad.net 1300
2. Setup OpenVPN interface and configure DHCP option
First, I created a directory under /config/user-data. This is the recommended place for configuration files, as files stored under that directory won't get overwritten by EdgeOS updates. I used /config/user-data/openvpn.I uploaded mullvad_ca.crt, mullvad_ca_mtr.conf, and mullvad_userpass.txt using scp to this folder and ran the following commands to setup the OpenVPN connection:
set interfaces openvpn vtun0 config-file /config/user-data/openvpn/mullvad_ca_mtr.conf
set interfaces openvpn vtun0 description 'Mullvad VPN tunnel'
Mullvad's public DNS server is 220.127.116.11. And while configuring it manually is not the prettiest thing, it looks like it has remained unchanged since 2019. Down the road, I could probably create an up/down script that will automatically set the DHCP DNS server option, but for now setting it manually should do:
delete service dhcp-server shared-network-name LAN2 subnet 192.168.20.0/24 dns-server 192.168.20.1
set service dhcp-server shared-network-name LAN2 subnet 192.168.20.0/24 dns-server 18.104.22.168
3. Configure NAT and firewall modify rules
At this point we should have a working OpenVPN connection, but because of the no route-pull option which was added to the configuration in the first step, no traffic will go through the VPN tunnel just yet.
To make things work, I created a NAT rule to masquerade the address range of eth2 (192.168.20.0/24) out vtun0:
set service nat rule 1000 description 'Mullvad VPN clients'
set service nat rule 1000 outbound-interface vtun0
set service nat rule 1000 source address 192.168.20.0/24
set service nat rule 1000 type masquerade
Then I created another routing table which will be used by the eth2 interface to exit through vtun0 instead of eth0:
set protocols static table 1 interface-route 0.0.0.0/0 next-hop-interface vtun0
Next, I created a modify firewall rule which makes all traffic from 192.168.20.0/24 use table 1 instead of the default table 0:
set firewall modify SOURCE_ROUTE rule 10 description 'Match traffic from 192.168.20.0/24 and use table 1'
set firewall modify SOURCE_ROUTE rule 10 source address 192.168.20.0/24
set firewall modify SOURCE_ROUTE rule 10 modify table 1
Finally, I attached the modify rule to the eth2 interface.
set interfaces ethernet eth2 firewall in modify SOURCE_ROUTE