Hardened Qubes VPN ProxyVM support for Qubes 4.3, nftables, strict DNS, and IPv6 disablement

Original forum link
https://forum.qubes-os.org/t/40786
Original poster
demosios
Created at
2026-04-23 10:19:34
Last wiki edit
2026-04-24 08:03:51
Revisions
2 revisions
Posts count
2
Likes count
2

Updated fork:

https://github.com/demosios/Qubes-vpn-support


Overview

I have published an updated fork of tasket/Qubes-vpn-support.

This work is based on the original Qubes VPN support project by @tasket. That project provided the core model and much of the structure for running a VPN client inside a dedicated Qubes ProxyVM. Credit belongs to @tasket for the original design and implementation.

I also want to credit @1choice for laying important groundwork for the shift toward nftables.

The goal of this fork is to update and harden the project for a modern Qubes OS 4.3 setup using nftables, with a stricter fail-closed security model.

Most existing VPN-in-Qubes approaches either rely heavily on manual firewall configuration, partially documented scripts, NetworkManager behavior, or older iptables assumptions. Those can work, but they are often less elegant, less complete, or harder to reason about under failure conditions.

This update keeps the Qubes-native ProxyVM model while making the firewall, DNS, IPv6, and startup behavior more explicit.


Primary Security Changes

Full architecture and change documentation:

https://github.com/demosios/Qubes-vpn-support/blob/master/README.md


Tested Baseline

OpenVPN remains the primary supported backend.

WireGuard support is now handled through a dedicated service rather than an optional systemd override. It should still be considered more operationally sensitive because WireGuard is kernel-driven and does not map as cleanly to the same userspace process-group egress model.


Quickstart

1. Install In The TemplateVM

In the TemplateVM:

cd Qubes-vpn-support
sudo bash ./install

Shut down the TemplateVM.


2. Create The VPN ProxyVM

Create a dedicated VPN ProxyVM from that template.

In Qubes settings for the VPN ProxyVM:

Start the VPN ProxyVM.


3. Initialize The VPN ProxyVM

In the VPN ProxyVM, select the backend explicitly.

For OpenVPN:

sudo /usr/lib/qubes/qubes-vpn-setup --config-openvpn

For WireGuard:

sudo /usr/lib/qubes/qubes-vpn-setup --config-wireguard

This prepares /rw/config/vpn/ for you and writes a persistent backend marker for that ProxyVM under one of:

/rw/config/vpn/backend-openvpn
/rw/config/vpn/backend-wireguard

4. Add VPN Provider Files

Add your provider files to:

/rw/config/vpn/

At minimum, provide:

/rw/config/vpn/vpn-client.conf

Also place any required certs, keys, CRLs, or other provider files in that directory.

If username/password authentication is needed for OpenVPN:

sudo /usr/lib/qubes/qubes-vpn-setup --userpass

For WireGuard, vpn-client.conf should be a wg-quick style config.


5. Configure Strict DNS

For strict hostname handling, configure VPN DNS in the provider config.

For OpenVPN:

setenv vpn_dns "X.X.X.X Y.Y.Y.Y"
remote vpn.example.net 1194

For WireGuard:

DNS = X.X.X.X, Y.Y.Y.Y
Endpoint = vpn.example.net:51820

For the strictest setup, use an IPv4 remote or endpoint address instead of a hostname.

Backend selection is now stored by the persistent marker files under /rw/config/vpn/, not by a WireGuard drop-in under /rw/config/qubes-vpn-handler.service.d/.


6. Start The Service

For OpenVPN:

sudo systemctl restart qubes-firewall.service
sudo systemctl restart qubes-vpn-handler.service
sudo systemctl status qubes-vpn-handler.service

For WireGuard:

sudo systemctl restart qubes-firewall.service
sudo systemctl restart qubes-wg-handler.service
sudo systemctl status qubes-wg-handler.service

7. Verify Before Attaching Downstream VMs

ip -br link
sudo nft list chain ip qubes custom-forward
sudo nft list chain ip qubes dnat-dns
cat /var/run/qubes/qubes-vpn-ns
cat /proc/sys/net/ipv6/conf/all/disable_ipv6
ls -l /rw/config/vpn/backend-openvpn /rw/config/vpn/backend-wireguard

Expected high-level results:

Only attach downstream AppVMs to the VPN ProxyVM after verifying the tunnel and DNS rules.


Testing And Feedback

This is security-sensitive networking code. Please test carefully before relying on it for important workloads.

Useful things to test:

If you find bugs, edge cases, provider-specific issues, or Qubes-version differences, please open an issue or submit a pull request.

The intent is to make this easier to audit and more robust for the community while preserving the basic architecture that made the original Qubes-vpn-support project useful.