These are the instructions that made it work for me.
First, from @turkja, with additions/ clarifications particularly in sections 5-7:
-
Create new TemplateVM based on Fedora/Debian template. For example
qvm-clone debian-11 debian-11-mullvad
Start a terminal in that TemplateVM
-
Copy the Mullvad installation .rpm/.deb to your TemplateVM (download it with internet-connected AppVM, verify signature, copy using Qubes tools (right-click, copy to other AppVM → debian-11-mullvad)
-
In the debian-11-mullvad TemplateVM, install the Mullvad .deb
So, something like sudo apt install ./MullvadVPN-2021.4_x86_64.deb
-
Shut down the template.
-
Next, create new AppVM, sys-vpn-mullvad, based on this template. Set the net qube as default (sys-firewall) Launch Settings after creation, and In the Advanced tab, click “provides networking”. When settings comes up, In the services tab, add network-manager with the + button. Under Applications add Mullvad VPN Unber Basic check Start qube automatically on boot
-
In the AppVM, configure bind-dirs for /etc/mullvad-vpn as explained here.
sudo mkdir -p /rw/config/qubes-bind-dirs.d
sudo touch /rw/config/qubes-bind-dirs.d/50_user.conf
echo “binds+=( '/etc/mullvad-vpn' )" | sudo tee /rw/config/qubes-bind-dirs.d/50_user.conf
Reboot.
-
In the AppVM, start the GUI, /opt/Mullvad VPN/mullvad-gui
Configure it to your taste.
Select the country
User Interface Settings >> Start Minimized
VPN Settings >> Launch App on Startup; Auto-connect; Local Network Sharing?; Kill Switch & Lockdown Mode; Tunnel Protocol ⇒ Wireguard
In a qube that you want to use with the VPN, say the Untrusted qube, in Settings >> Basic, change the Net qube to sys-vpn-mullvad
Start a terminal in the Untrusted (or other) qube
Try ping google.com
. If you end up with a name resolution error, then, following @cobordism:
In the AppVM, sys-vpn-mullvad, start a terminal
Run sudo /usr/lib/qubes/qubes-setup-dnat-to-ns
If name resolution now works in the Untrusted qube, then use the approach of @tngbng:
Start a terminal in the Mullvad TemplateVM, debian-11-mullvad
In the file /etc/NetworkManager/dispatcher.d/qubes-nmhook
, insert the command sleep 5
before:
sudo /usr/lib/qubes/qubes-setup-dnat-to-ns
Restarting the AppVM and then the Untrusted qube, name resolution should work.
Finally, follow the instructions at Mullvad to add the DNS hijacking rules in the AppVM.
(For some reason, these stick after a reboot despite bind-dirs not having been configured for /rw/config.)
To find out your vif* IP address, run `ip a | grep -i vif`
Edit the firewall user file with nano:
`sudo nano /rw/config/qubes-firewall-user-script`
Copy and paste the following in the bottom.
Replace 10.137.0.47 with your own vif* IP address:
# replace 10.137.0.47 with the IP address of your vif* interface
virtualif=10.137.0.47
vpndns1=10.64.0.1
iptables -F OUTPUT
iptables -I FORWARD -o eth0 -j DROP
iptables -I FORWARD -i eth0 -j DROP
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
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
Then add the qube firewall rules to the Settings manager for the AppVM:
Click on the "Firewall rules" tab.
Click on "Limit outgoing internet connections to ...".
Click on "+" and enter the IP addresses of the VPN servers that you want to be able to connect to. You can find it in the WireGuard configuration file (mlvd-se9.conf) on the Endpoint line, or in our [Servers list](https://mullvad.net/servers/).
Click on OK.
If you have to add more servers later you can do it in the Terminal Emulator using the following command (replace SERVER-IP with the IP-address to the Mullvad VPN server).
`qvm-firewall MullvadVPN add accept dsthost=SERVER-IP`
Than also disable ping replies:
Click on the Qubes app menu and open Terminal Emulator (for dom0)
Run `qvm-firewall sys-vpn-mullvad list`
Find the rule in the bottom that says `accept icmp` and note the line number.
Run `qvm-firewall sys-vpn-mullvad del --rule-no NUMBER`. Replace NUMBER with the line number you found above.
Run `qvm-firewall sys-vpn-mullvad add --before NUMBER drop proto=icmp`. Replace NUMBER with the line number you found above. This new rule will be added before the last "drop" line.
Check it 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.
Troubleshooting if the Internet works in the ProxyVM, but not in the AppVM.
Make sure you shut down your AppVM before setting the Networking to ProxyVM. It seems that it does not work as well to change it on the fly.
Try to lower the MTU in your AppVM:
`sudo ip link set mtu 1200 eth0`