Mullvad on Qubes OS 4

Other VPN software 

Last updated:

In this guide we will set up a ProxyVM called "MullvadVPN", which will provide network to other AppVMs.
This guide is using OpenVPN. If you want to use WireGuard instead then see the guide WireGuard on Qubes OS.

Note: We will use Mullvad servers in Sweden to connect to in this guide. If you want to use another country then replace the configuration with that.

Create a new qube

First install the Debian 12 template (if you do not already have it) using the following command in the Terminal Emulator (dom0):

sudo qubes-dom0-update qubes-template-debian-12

Click on the Qubes app menu > Qubes Tools > Create Qubes VM.

  1. Name and label: MullvadVPN.
  2. Type: AppVM (persistent home, volatile root) or StandaloneVM (fully persistent).
  3. Template: debian-12 (or later).
  4. Networking: default (sys-firewall).
  5. Click on the Advanced tab and check (enable) Provides network access to other qubes.
  6. Click on OK.

The newly created MullvadVPN AppVM qube will show up as "Service: MullvadVPN" in the Qubes app menu and not "Qube: MullvadVPN" due to its "provides network" setting.

Download an OpenVPN configuration

In another AppVM (not MullvadVPN) that you use for web surfing:

  1. Open a browser and log in to our OpenVPN configuration file generator.
  2. Select Linux as the platform.
  3. Select Sweden a the country and Gothenburg or Malmö or Stockholm as the city.
  4. Click on Download zip archive.
  5. Open the Downloads folder and right click on the downloaded OpenVPN file.
  6. Select Copy To Other AppVM... and then enter MullvadVPN as the Target and click on OK.

Install OpenVPN

We will install WireGuard in the Debian-12 template so your MullvadVPN ProxyVM can use that.

  1. Click on the Qubes app menu and go to Template: debian-12 and open the Terminal.
  2. In the Terminal run the command sudo apt install openvpn -y
  3. Disable the OpenVPN service: sudo systemctl disable openvpn.service
  4. Shut down the VM with the command sudo shutdown -h now
  5. Click on the Qubes app menu and go to System Tools > Qube Manager.
  6. In Qube Manager, restart the MullvadVPN ProxyVM (so that OpenVPN is added to it).

In the Qubes Manager

Assign a AppVM to exit via the MullvadVPN proxy (the AppVM must be started and assigned to the ProxyVM otherwise the vif on the ProxyVM will not be visible).

  1. Shut down that AppVM you wish to assign
  2. Select a AppVM right-click it and then select Qube settings  (or preferences if using the applet)
  3. In the Basic tab, change Networking: to  MullvadVPN
  4. Click on Apply and then OK
  5. Start the AppVM again.

In the MullvadVPN ProxyVM

Install OpenVPN

In Debian10, you can of course install a newer one if you wish as well.

In a terminal run sudo apt-get update && sudo apt-get install openvpn

Extract and copy the configuration files to /etc/openvpn

  1. In a terminal change directory to where the configuration file is located
  2. unzip the file (unzip mullvad_config_linux_se.zip)
  3. To copy the files to /etc/openvpn/, run  sudo cp mullvad_config_linux_se/* /etc/openvpn/
  4. To set the execute permissions on it, run sudo chmod 755 /etc/openvpn/update-resolv-conf

Enable autostart of OpenVPN

Issue  sudo vi /etc/default/openvpn and change #AUTOSTART="all" to AUTOSTART="all" (in other words, remove the "#")
After that save and exit.

Add DNS hijacking script

Add the following to the file /rw/config/qubes-firewall-user-script be sure to change 10.137.0.47 to the IP that matches your vif*

To find out your vif* ip address, run ip a | grep -i vif in a terminal (make sure you have the AppVM assigned before you do this, otherwise it will not show up).

#!/bin/bash
# replace 10.137.0.47 with the IP address of your vif* interface
virtualif=10.137.0.47
vpndns1=10.8.0.1
vpndns2=10.14.0.1
iptables -F OUTPUT
iptables -I FORWARD -o eth0 -j DROP
iptables -I FORWARD -i eth0 -j DROP
iptables -F PR-QBS -t nat
iptables -A PR-QBS -t nat -d $virtualif -p udp --dport 53 -j DNAT --to $vpndns1
iptables -A PR-QBS -t nat -d $virtualif -p tcp --dport 53 -j DNAT --to $vpndns1
iptables -A PR-QBS -t nat -d $virtualif -p udp --dport 53 -j DNAT --to $vpndns2
iptables -A PR-QBS -t nat -d $virtualif -p tcp --dport 53 -j DNAT --to $vpndns2

This is to redirect DNS requests to 10.8.0.1 and 10.14.0.1 for all AppVMs that use the ProxyVM.

In Qubes Manager (again)

Select MullvadVPN then right-click and select Qube settings

Make the following changes:

  1. Ensure it is set to use sys-firewall as "Networking"
  2. Check "Start qube automatically on boot"
  3. Click on "Firewall rules"
  4. Click on "Limit outgoing internet connections to ..."
  5. Click on "+" and then enter the IP addresses of the VPN servers you wish to connect to.
  6. Click on Apply and then OK

For instance if you wish to connect to us-nyc-001.mullvad.net, then issue "nslookup us-nyc-001.mullvad.net" in a terminal and then enter that IP address (see our list of VPN servers), or you can download an OpenVPN configuration file with Use IP Addresses enabled in the Advanced settings and then look at the OpenVPN configuration for which IP-addresses it contains and then add them.

You can also enter IP ranges for Sweden and the Netherlands (ensure you add all IP ranges for a given location):

  •     45.83.220.0/24  Sweden (Malmö)
  •   141.98.255.0/24  Sweden (Malmö)
  • 193.138.218.0/24  Sweden (Malmö)
  • 185.213.152.0/24  Sweden (Helsingborg)
  • 185.213.154.0/24  Sweden (Gothenburg)
  •   185.65.135.0/24  Sweden (Stockholm)
  •   185.65.134.0/24  Netherlands (Amsterdam)

In Dom0

In Qubes R4 "ICMP and DNS are no longer accessible in the GUI, but can be changed via qvm-firewall".

  1. Open Terminal Emulator
  2. Run qvm-firewall MullvadVPN list. Based on that list we need to delete the rule that accepts icmp, and add a new rule that drops it.
  3. Run qvm-firewall MullvadVPN del --rule-no [icmp_rule_#]. Now to add the new icmp rule run the list command again, and add the icmp rule before the final "drop" line
  4. Run qvm-firewall MullvadVPN add --before [last_drop_rule_#] drop proto=icmp. Now you can verify by running the list command again. The rules should be in this order: accept -> the IP addresses of the VPN servers, accept -> dns, drop -> icmp, drop

Keep in mind that you will need to edit the firewall rules in dom0 if you wish to add more ip-ranges.

FAQ

How do I verify that traffic is going out via the MullvadVPN proxy?

Open a browser in your APPVM that is connected to the MullvadVPN proxy VM and go to our Connection check.

Why do you use a standalone VM?

You can of course do this in a regular AppVM as long as you have OpenVPN installed in it, having it standalone means you do not need to restart VM's as much if you want to update things, though it does take more diskspace.

I sometimes can't connect. Why?

Since OpenVPN will depend on DNS working unless you use IP addresses, it could be because your DNS replies are poisoned, or your DNS queries are blocked, the solution would then be to use IP addresses instead of host+domainnames for connecting. Open the OpenVPN configuration file located in /etc/openvpn/ and replace "remote se.mullvad.net" with "remote 193.138.218.131" (as a test, and if that works you can add more entries)

I followed the guide but can't connect to anything from the APPVM. However, the PROXYVM connects properly and everything works there.

Make sure you shut down your APPVM before setting the PROXYVM, it seems it does not work as well by changing it on the fly as it did in Qubes 3.2.