How do I setup VPN proxy VM with default fedora-43-xfce template using OpenVPN?

I’ve researched for long how to setup a VPN VM, on this forum and elsewhere on the worldwideweb, and I am unable to find an easy, straightforward solution to create a VPN Qube or proxy VM with the default Fedora 43 as the template. Am I missing a package? Am I setting up the Qube settings wrong.

I tried this tutorial I link to hereafter. The VPN connection was established and the VPN Qube had internet and an active VPN connection. The networking service was enabled. I assume this means that the template has the needed packages to run OpenVM.

I enabled provide network in the proxy VM settings. I connected the VMs in this schema: sys-net > sys-firewall > Proxy-VM > sys-firewall2 > AppVM. The AppVM did not have internet connection.

I tried to read many other VPN tutorials. Some are outdated. Some are for Debian only. Some are incredibly complex and assume advanced technical knowledge.

Would anyone have a guide somewhere for for Qubes 4.3 running Fedora 43, or an update for the guideline linked to above?

Should’t there be an official tested and working guideline for those running Qubes for first time and who do not have time and do not trust their ability to learn lengthy terminal codes to manage firewall and VPN kill switches?

I’ve been trying to fix. It’s frustrating. The AppVM does connect to the VPN and Firefox in the AppVM does access the internet, only on occasions and for some of the VPN servers. AppVM may initially connect and then disconnect and vice versa. There’s s one more problem. ping 1.1.1.1 from within the AppVM always returns a valid connection, with or without a VPN connected in the proxy VM, and even when browser in the AppVM unable to connect to the Internet. I think there’s a dns problem?

I agree. Given the number of active guides and threads on this topic, there’s clearly demand. We did have qubes-tunnel in the QubesOS-contrib repository, but as of now it’s no longer available with r4.3.

Sounds like it and, in my sys-vpn setup experience, dns is usually the last tweak before it finally just works. This problem is not Fedora/vpn specific though, so don’t limit yourself to Fedora, or vpn, specific guides. I’ve had success with Solene’s guides when struggling with the dns setup..

FWIW, I gave up on setting up a VPN proxy netvm according to the instructions I found, and just use NetworkManager in the app qube. The security implication is that the qube has access to my VPN credentials, which has been OK for my threat model: that qube does not connect to the open internet, but just to my employer’s intranet.

Is there really no threat model for which a proxy/VPN VM connected to a work AppVM makes sense? It seems like it.

Furthemore, if someone opts for Fedora (SE Linux) protection but inserts a Debian (even if minimal) proxy VM between between Fedora AppVM and Fedora sys-firewall, then is it weakening security? Unless network manager itself holds a vulnerability and you seek to isolate it from work AppVM in a proxy VM?

@ncm have you enable in AppVM Qubes settings service network-manager?

Hey,

Many guides miss a critical detail: ip forwarding could be missing and the nftables rules must be applied inside the VPN VM itself, and they must correctly identify downstream AppVM interfaces. In Qubes, these interfaces are named vifX.Y (e.g., vif12.1). Using a generic vm* pattern can sometimes be unreliable; vif* is the correct wildcard to automatically match any connected AppVM.

The goal is strict routing:

  1. Allow traffic from any AppVM (vif*) to exit only via the VPN tunnel (tun0).
  2. Block any traffic from AppVMs trying to exit via the physical interface (eth0).
  3. Prevent the VPN VM’s own local traffic from being forwarded to AppVMs.

Here are the exact steps to apply this in your VPN Proxy VM:

1. Enable IP Forwarding

Allow the kernel to forward packets:

sudo sysctl -w net.ipv4.ip_forward=1

To make it permanent:

echo "net.ipv4.ip_forward=1" | sudo tee /rw/config/rc.local

2. Apply the NFT Rules

Run these commands inside your VPN Proxy VM. These rules use vif* to automatically catch any AppVM connected to this Proxy VM.

Important Note:

Check your actual ip interface using command “ip link”

In this guide tun0 is assumed as your vpn tunnel and eth0 as your main internet source. If this is different, you must replace this to make it work successfully.

Step A: Allow AppVM traffic ONLY to the VPN Tunnel
This rule matches any interface starting with vif (any AppVM) and allows traffic only if it goes out tun0.

sudo nft add rule inet qubes-forwarding forward iifname "vif*" oifname "tun0" accept

Step B: BLOCK AppVM traffic from going to eth0 (Prevent Leakage)
This is the security critical step. If traffic from an AppVM (vif*) tries to exit the physical eth0, drop it immediately.

sudo nft add rule inet qubes-forwarding forward iifname "vif*" oifname "eth0" drop

To make it permanent: You can add the nft rules to:

/rw/config/nftcustomrules.conf

Hope this helps!

Cheers!

It is easy to identify circumstances where using a proxy/VPN VM that attaches to a work VPN makes sense. Yes, I enabled NetworkManager in this work AppVM. Not because there is anything wrong with a proxy/VPN VM, but just because I failed to get it to work using the instructions published, when I last tried it.

Thank you for all your suggestions. No matter what I did, ping 1.1.1.1 ALWAYS returns a valid internet connection, even when the VPN is disconnected and firewall enabled in Qubes Settings Firewall. In /rw/config/qubes-firewall-user-script I put all the following texts (do not ask me what they mean please; i just copy/pasted from this forum). None worked.

sudo nft add rule qubes custom-forward oifname eth0 counter drop
sudo nft add rule ip6 qubes custom-forward oifname eth0 counter drop

sudo nft add rule inet qubes-forwarding forward iifname “vif*” oifname “tun0” accept
sudo nft add rule inet qubes-forwarding forward iifname “vif*” oifname “eth0” drop

DNS=9.9.9.9
nft add chain qubes nat { type nat hook prerouting priority dstnat; }
nft add rule qubes nat iifname == “vif*” tcp dport 53 dnat “$DNS”
nft add rule qubes nat iifname == “vif*” udp dport 53 dnat “$DNS”