QubesOS R4: Wireguard VPN
Wireguard is a new-age VPN protocol that is fast and secure. Here’s how to seamlessly integrate this as a Debian-based AppVM in your QubesOS R4 network stack using Mullvad VPN as the service provider.
Table of Contents
TemplateVM
Install required packages
In the TemplateVM, start by installing wireguard-tools and other prequisites.
We include cURL to retrieve files from Mullvad repositories and openresolv to fix problems with the inferior Debian version of resolvconf.1
2
3
4
5
6
7
8
9
10# Change to superuser
sudo su -
# Activate unstable sources for Apt
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' > /etc/apt/preferences.d/limit-unstable
apt update
# Install
apt install wireguard-tools curl openresolv
Dom0
Create ‘sys-vpn’ AppVM
In dom0, create a new AppVM aka ProxyVM to provide the VPN network interface. This will be a Debian-based HVM (in-VM kernel) AppVM that will be used to compile and host the wireguard.ko kernel module.
We use a HVM-style AppVM because we need to install build-related packages (linux-headers etc) to successfully compile the module. It’s not possible to successfully compile the module with the dom0 kernel.1
2# Create HVM AppVM named 'sys-vpn'
qvm-create --class AppVM --template d9-template --label green --property virt_mode=hvm --property kernel="" --property provides_network=True sys-vpn
AppVM ‘sys-vpn’
Compile and install wireguard.ko kernel module
1 |
|
Set up the module loader
1 |
|
Restart the AppVM using these commands in dom0:1
2qvm-shutdown sys-vpn
qvm-start sys-vpn
Set up the DNS and anti-leak firewall rules
Once the sys-vpn AppVM has restarted, download or create the a startup hook file /rw/config/qubes-ip-change-hook
#!/bin/sh
ns=$(cat /etc/resolv.conf | grep -v '^#' | grep nameserver | awk '{print $2}')
NS1=$(echo ${ns} | cut -d " " -f 1) # 10.139.1.1
NS2=$(echo ${ns} | cut -d " " -f 2) # 10.139.1.2
NS_MULLVAD_PRIVATE=10.8.0.1
NS_MULLVAD_PUBLIC=193.138.219.228
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 $NS1 -p udp --dport 53 -j DNAT --to $NS_MULLVAD_PUBLIC
iptables -A PR-QBS -t nat -d $NS1 -p tcp --dport 53 -j DNAT --to $NS_MULLVAD_PUBLIC
iptables -A PR-QBS -t nat -d $NS2 -p udp --dport 53 -j DNAT --to $NS_MULLVAD_PUBLIC
iptables -A PR-QBS -t nat -d $NS2 -p tcp --dport 53 -j DNAT --to $NS_MULLVAD_PUBLIC
1 |
|
Install Mullvad VPN config files
The Mullvad VPN config files need to be installed in the TemplateVM, but can only be downloaded using an AppVM. Download them then copy them across to the TemplateVM.
1 |
|
TemplateVM (a second time)
Copy Mullvad VPN files to /etc/wireguard
1 |
|
To pass this update to dependant AppVMs, shut down the TemplateVM and restart the AppVM using these commands in dom0:1
2
3
4
5
6# Shut down the TemplateVM
qvm-shutdown d9-template
# Restart the AppVM
qvm-shutdown sys-vpn
qvm-start sys-vpn
All done!
Finalise
Test it!
All Wireguard commands need to be executed in the sys-vpn AppVM.1
2
3
4
5# Manually activate the DNS hook
sudo /rw/config/qubes-ip-change-hook
# Use wg-quick to activate a connection ('mullvad-se1')
sudo wg-quick up mullvad-se1
Make it permanent
Add the activation command to /rw/config/rc.local
to connect at VM startup. There’s no need to include the hook script, as this will be executed automatically by QubesOS.1
echo 'wg-quick up mullvad-se1' | sudo tee --append /rw/config/rc.local
Diagnostics and Wireguard Commands
Is my Mullvad connection active?
Check this using these commands in the sys-vpn AppVM:1
2
3
4
5
6
7
8
9
10
11
12
13
14# Check Wireguard status
sudo wg show
#> interface: mullvad-ca1
#> public key: Tbzsvqmx0kXLtb+2EZnb46gaY3jdLrVIVeJRYR22QTE=
#> private key: (hidden)
#> listening port: 52272
#> fwmark: 0xca6c
#>
#> peer: BQVUyn4F0NlbALK0ksCi4pY9d6/adMaXPdtjKgoL41E=
#> endpoint: 198.144.156.48:51820
#> allowed ips: 0.0.0.0/0, ::/0
#> latest handshake: 2 minutes, 8 seconds ago
#> transfer: 109.45 MiB received, 5.44 MiB sent
If results like the above are returned, you’re connected! If you’re not connected, the command will present no output.
Change to a different exit node
1 |
|
Other networking diagnostics
See this post: Linux Network Diagnostics Cheetsheet
References and Credits
Thanks to the following publishers and resources, without whose articles I wouldn’t have been able to complete my own setup nor this guide.