In this guide we will setup a ProxyVM called MullvadVPN, which will then proxy other APPVMs traffic.
Note: We will use Sweden as a region in this guide, if you prefer another region then replace se with that one.
This guide is using OpenVPN. For using WireGuard see the guide WireGuard on Qubes OS.
First install a Debian 10 template (if you do not already have it) by issuing the following in dom0:
sudo qubes-dom0-update --enablerepo=qubes-templates-itl-testing qubes-template-debian-10
- Click Create Qubes VM in Applications
- Name and label: MullvadVPN
- Type: Standalone qube copied from a template
- Template: debian-10
- Networking: default (sys-firewall)
- Advanced: Check provides network
In an AppVM
- Open a browser and go to our Configuration files page.
- Enter your account number, select Linux as platform and then the region you wish to use then click on the Download button.
- Open a terminal and qvm-copy the downloaded .zip file(for instance mullvad_config_linux_se.zip) to the ProxyVM you created (MullvadVPN).
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).
- Shut down that AppVM you wish to assign
- Select a AppVM right-click it and then select Qube settings (or preferences if using the applet)
- In the Basic tab, change Networking: to MullvadVPN
- Click on Apply and then OK
- Start the AppVM again.
In the MullvadVPN ProxyVM
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
- In a terminal change directory to where the configuration file is located
- unzip the file (unzip mullvad_config_linux_se.zip)
- To copy the files to /etc/openvpn/, run
sudo cp mullvad_config_linux_se/* /etc/openvpn/
- 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:
- Ensure it is set to use sys-firewall as "Networking"
- Check "Start qube automatically on boot"
- Click on "Firewall rules"
- Click on "Limit outgoing internet connections to ..."
- Click on "+" and then enter the IP addresses of the VPN servers you wish to connect to.
- 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):
- 184.108.40.206/24 Sweden (Malmö)
- 220.127.116.11/24 Sweden (Malmö)
- 18.104.22.168/24 Sweden (Malmö)
- 22.214.171.124/24 Sweden (Helsingborg)
- 126.96.36.199/24 Sweden (Gothenburg)
- 188.8.131.52/24 Sweden (Stockholm)
- 184.108.40.206/24 Netherlands (Amsterdam)
In Qubes R4 "ICMP and DNS are no longer accessible in the GUI, but can be changed via qvm-firewall".
- Open Terminal Emulator
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.
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
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.
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 220.127.116.11" (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.