1. INSTALL TEMPLATE (fedora-40-minimal) AND UPDATE IT
Open dom0 terminal and type: > sudo qubes-dom0-update qubes-template-fedora-40-minimal && sudo qvm-run -u root --pass-io fedora-40-minimal "xterm -e 'dnf update && dnf upgrade && dnf autoremove && read'" && qvm-shutdown fedora-40-minimal
2. CLONE TEMPLATE & CREATE VPN TEMPLATE
dom0: > qvm-clone fedora-40-minimal f40m-vpn && qvm-run -u root --pass-io f40m-vpn "xterm -e 'dnf install qubes-input-proxy-sender qubes-core-agent-passwordless-root qubes-core-agent-networking qubes-core-agent-dom0-updates qubes-core-agent-network-manager NetworkManager-wifi network-manager-applet notification-daemon thunar qubes-core-agent-thunar qubes-menus pciutils iputils less psmisc gnome-keyring chromium dbus-x11 dejavu-sans-fonts tinyproxy notification-daemon xfce4-terminal nethogs geany openvpn openssl && read'"
3. FIXING freedesktop.notifications.service VPN TEMPLATE
dom0: > qvm-run -u root f40m-vpn 'geany /usr/share/dbus-1/services/org.freedesktop.Notifications.service'
when geany prompts copy and paste the text below then save the file and shutdown the template.
[D-BUS Service]
Name=org.freedesktop.Notifications
Exec=/usr/libexec/notification-daemon
4. CREATE APPVM-VPN
> qvm-create --template f40m-vpn --class AppVM --label red default-f40m-vpn && qvm-prefs default-f40m-vpn provides_network on
5. SETUP FILES/SCRIPTS INSIDE DEFAULT-APPVM-VPN 5.1 Create vpn directory: >qvm-run -u root --pass-io --nogui default-f40m-vpn 'mkdir /rw/config/vpn'
5.2 Edit /rw/config/qubes-firewall-user-script
> qvm-run -u root default-f40m-vpn 'geany /rw/config/qubes-firewall-user-script'
copy and paste this:
#!/bin/bash
# Block forwarding of connections through upstream network device
# (in case the vpn tunnel breaks):
# Prevent the qube to forward traffic outside of the VPN
nft insert rule qubes custom-forward oifname eth0 counter drop
nft insert rule ip6 qubes custom-forward oifname eth0 counter drop
nft insert rule qubes custom-forward iifname eth0 counter drop
nft insert rule ip6 qubes custom-forward iifname eth0 counter drop
# Add the `vpntunnel` group to system, if it doesn't already exist
if ! grep -q "^vpntunnel:" /etc/group ; then
sleep 3s
groupadd -rf vpntunnel
sync
fi
sleep 2s
# Accept traffic to VPN
nft 'add chain qubes output { type filter hook output priority 0; policy accept; }'
# Allow traffic from the `vpntunnel` group to the uplink interface (eth0);
# Our VPN client will run with group `vpntunnel`.
nft insert rule ip qubes output oifname eth0 skgid vpntunnel accept
While using geany app create a new file named qubes-vpn-status.sh and save it in /rw/config/vpn/ folder with this content:
#!/bin/bash
set -e
export PATH="$PATH:/usr/sbin:/sbin"
case "$1" in
up)
# To override DHCP DNS, assign DNS addresses to 'vpn_dns' env variable before calling this script;
# Format is 'X.X.X.X Y.Y.Y.Y [...]'
if [[ -z "$vpn_dns" ]] ; then
# Parses DHCP foreign_option_* vars to automatically set DNS address translation:
for optionname in ${!foreign_option_*} ; do
option="${!optionname}"
unset fops; fops=($option)
if [ ${fops[1]} == "DNS" ] ; then vpn_dns="$vpn_dns ${fops[2]}" ; fi
done
fi
nft flush chain ip qubes dnat-dns
if [[ -n "$vpn_dns" ]] ; then
# Set DNS address translation in firewall:
for addr in $vpn_dns; do
nft add rule qubes dnat-dns iifname == "vif*" tcp dport 53 dnat "$addr"
nft add rule qubes dnat-dns iifname == "vif*" udp dport 53 dnat "$addr"
done
su - -c 'notify-send "$(hostname): LINK IS UP." --icon=network-server' user
else
su - -c 'notify-send "$(hostname): LINK UP, NO DNS!" --icon=dialog-error' user
fi
;;
down)
su - -c 'notify-send "$(hostname): LINK IS DOWN !" --icon=dialog-error' user
# Restart the VPN automatically
sleep 5s
sudo /rw/config/rc.local
;;
esac
5.3. CHANGES IN /rw/config/rc.local
using geany open the file /rw/config/rc.local
copy and paste this content and then save it:
#!/bin/bash
VPN_CLIENT='openvpn'
VPN_OPTIONS='--cd /rw/config/vpn/ --config openvpn-client.ovpn --daemon'
# vpntunnel
sudo sg vpntunnel -c "$VPN_CLIENT $VPN_OPTIONS"
5.4 Make some files with chmod and shutdown default-appvm-vpn
dom0: > qvm-run -u root --pass-io --nogui default-f40m-vpn 'chmod +x /rw/config/vpn/qubes-vpn-status.sh' && qvm-run -u root --pass-io --nogui default-f40m-vpn 'chmod +x /rw/config/rc.local' && qvm-run -u root --pass-io --nogui default-f40m-vpn 'chmod +x /rw/config/qubes-firewall-user-script' && qvm-shutdown default-f40m-vpn
Now you have created a default vpn template and appvm, from this one you can clone and make many appvms-vpns you want.
6. Clone the default-f40m-vpn to use with your config files..
dom0: > qvm-clone default-f40m-vpn sys-vpn-test
Start sys-vpn-test copy all your vpn config files into the folder /rw/config/vpn/
Edit your .ovpn file and inside it add the lines
ATTENTION: rename your .ovpn file to openvpn-client.ovpn
script-security 2
up 'qubes-vpn-status up'
down 'qubes-vpn-status down'
Save it in /rw/config/vpn/ renamed to: openvpn-client.ovpn
the folder /rw/config/vpn/ inside sys-vpn-test, in this example the keys/certs was gen separated, it will look like this:
Restart your sys-vpn-test and if you have done everything right you'll be able to use it, run a dispvm, change the net-qube to sys-vpn-test browser to ipleak.net and test it, while running the test you can check in vpn terminal the connection using: sudo nethogs.