IVPN App 4.2 setup guide

Intro

This guide explains how to setup a a VPN with IVPN app on Qubes OS 4.2 using a Fedora template.

IVPN app is open source and they provide repositories for fedora / debian, there is an official documentation but I think it deserves more explanations here: IVPN on Qubes OS - IVPN Help

The App supports OpenVPN and WireGuard tunnels with respectively obfuscation protocols obfsproxy and V2ray.

They seem also a legit service to use as per the trustable source Private VPN Service Recommendations and Comparison, No Sponsors or Ads - Privacy Guides

If you want to set up IVPN using WireGuard without the App, see Wireguard VPN setup

Setup

Qube creation

  • Create a dedicated qube for the vpn
    • Name it as you want (I will name it sys-vpn-ivpn-app)
    • Choose type “Standalone” with the template fedora-38 (or xfce flavor, minimal flavor should work too)
    • Check “provide network access to other qubes” in the Advanced settings tab
  • In the qube settings
    • Give it 800 MB of memory minimum
    • Add the service qubes-firewall

Qube configuration

  • Start the qube
  • Follow the official guide to install IVPN app, which is just:
    • sudo dnf config-manager --add-repo https://repo.ivpn.net/stable/fedora/generic/ivpn.repo
    • sudo dnf install ivpn-ui
  • Add the following code to /rw/config/rc.local this is required to automatically switch the DNS offered by the NetVM to the qubes, in addition this code automatically repatch IVPN code when the program is upgraded
if ! grep "QUBES OS" /opt/ivpn/etc/firewall.sh >/dev/null
then
    sudo sed -i '/-set_dns/a\
      #QUBES OS - specific operation\
      systemctl restart systemd-resolved || echo "Error: systemd-resolved" \
      /usr/lib/qubes/qubes-setup-dnat-to-ns || echo "Error: failed to run /usr/lib/qubes/qubes-setup-dnat-to-ns"' /opt/ivpn/etc/firewall.sh
fi
  • Reboot the qube
  • Proceed to next step

IVPN App

Start the App with /opt/ivpn/ui/bin/ivpn-ui or add “IVPN” application in the qube menu entry.

The IVPN app should start without issue:

  • Enter your credentials
  • Connect
  • Go in Settings and then Dns
    • Enable “Force management of DNS using resolv.conf” ( :warning: this is really important)
  • Configure the App as you want

Auto start at boot can be enabled in the settings “General”.

Avoid issues with WireGuard

:information_source: WireGuard tunnels can trigger a MTU issue in the network, in short it could make some websites not working (like duckduckgo) because of too big packet sizes. This is a common issue with WireGuard VPNs.

Add this to /rw/config/qubes-firewall-user-script

nft add rule ip qubes custom-forward tcp flags syn / syn,rst tcp option maxseg size set rt mtu

This will automatically ensure that the qubes network packets will fit in a WireGuard network packet and will make things works©.

Killswitch configuration

:information_source: You may want to force all qubes traffic to go through the VPN and block non-VPN traffic. IVPN app offers a killswitch but the app could still crash and the killswitch wouldn’t be guaranteed to work.

Add the rules below in /rw/config/qubes-firewall-user-script in the qube:

# Prevent the qube to forward traffic outside of the VPN
nft add rule qubes custom-forward oifname eth0 counter drop
nft add rule ip6 qubes custom-forward oifname eth0 counter drop

Optional hardening: Avoid DNS leaks

:information_source: You may also want to force using a defined DNS server (9.9.9.9 in the current example) and blocking all other DNS servers (this avoids dns leaks)

# Redirect all the DNS traffic to the preferred DNS server
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"

Access local LAN / addresses (Advanced users /!\ )

:information_source: There is an issue with the App on Qubes OS, the “allow LAN exception doesn’t always work”, it’s not useful for most users though, don’t panic :smiley:

I created a script /rw/config/bypass-fw with the content (adapt the IPs in the first variable):

#!/bin/sh

IPS_TO_ALLOW="10.42.42.42 10.42.42.150"

for i in "$IPS_TO_ALLOW"
do
  nft insert rule qubes custom-forward ip daddr $i counter accept
  nft insert rule filter FORWARD ip daddr $i counter accept
  nft insert rule filter FORWARD ip saddr $i counter accept

Make it executable with chmod +x /rw/config/bypass-fw, make sure to change the script in /rw/config/rc.local to call /rw/config/bypass-fw like this:

if ! grep "QUBES OS" /opt/ivpn/etc/firewall.sh >/dev/null
then
    sudo sed -i '/-set_dns/a\
      #QUBES OS - specific operation\
      systemctl restart systemd-resolved || echo "Error: systemd-resolved" # this line is required for Qubes OS 4.2 (tested on Qubes OS 4.2-RC4)\
      /usr/lib/qubes/qubes-setup-dnat-to-ns || echo "Error: failed to run /usr/lib/qubes/qubes-setup-dnat-to-ns"' /opt/ivpn/etc/firewall.sh
      /rw/config/bypass-fw
fi

Make sure to edit /opt/ivpn/etc/firewall.sh to add /rw/config/bypass-fw around where the code above is added within the file.

4 Likes

I think you need to add RST flag as well as recommended by iptables manual:
https://manpages.debian.org/stretch/iptables/iptables-extensions.8.en.html#TCPMSS
I guess some hosts can send TCP RST on MTU issue.

The appropriate nft command would be:
nft add rule ip qubes custom-forward tcp flags syn / syn,rst tcp option maxseg size set rt mtu
https://git.netfilter.org/iptables/commit/?id=1c934617f661dc0bc471c0f0b4ace254c55182df

1 Like

It seems to be better indeed, thank you :slight_smile:

I updated the system to version 4.2 however, i use appvm for this supplier made when i was in version 4.1 is that wrong? because all works fine. i copied these vm and added the commands you wrote to the test also on this vm works well, is that good, bad? i tested on the dnsleak page and everything is okay so the question which vm to use and can these configurations be considered correct and safe?

That’s fine, just make sure your firewall rules (if any) are still working.

Also, make sure that in the upgrade process you also updated the template. And unrelated to the upgrade, make sure you are using a supported template, not a EOL one, so fedora 38 or debian 12 or a community managed template such as gentoo, arch linux etc… :slight_smile:

1 Like

Used this guide to hide that I’m using Tor. Additional steps:

  1. change netvm for your proxyvm (sys-vpn) to sys-whonix

  2. change Protocol/Port in IVPN app to OpenVPN/TCP 443 (because Tor can’t handle UDP)

That’s only for using tor to connect to the VPN (just to make things clear if someone reads the thread).

If using Tor through the VPN, no changes are required :+1:

I did that but the dns is corrupted. Other VM’s web pages won’t open because of dns corruption, but the network works fine.

@solene The VPN works good, but when I try to use from another App Qube the internet doesn’t work but in qube itself works perfectly fine.
I made everything you said, I made that this qube that provides internet, added network-manager service and everything but it doesn’t seem to work with IVPN. The other VPN providers works good.
What can be the problem ?

does your qubes resolve DNS names?

What does ping -c 4 quad9.net output? If nothing, what about ping -c 4 9.9.9.9 ?

I’m sorry that I am replying from different account (used temp login info)

pinging quad9 does nothing like you guesed but pinging 9.9.9.9 it’s working fine.
What should be the problem ?

--- 9.9.9.9 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms

did you apply the changes to ivpn file firewall.sh to force Qubes OS DNS propagation?

# Redirect all the DNS traffic to the preferred DNS server
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"

You mean this ?, where I am supposted to put this ?

I meant this step

if ! grep "QUBES OS" /opt/ivpn/etc/firewall.sh >/dev/null
then
    sudo sed -i '/-set_dns/a\
      #QUBES OS - specific operation\
      systemctl restart systemd-resolved || echo "Error: systemd-resolved" \
      /usr/lib/qubes/qubes-setup-dnat-to-ns || echo "Error: failed to run /usr/lib/qubes/qubes-setup-dnat-to-ns"' /opt/ivpn/etc/firewall.sh
fi

Avoid a standalone VM with the following:

INSIDE THE TEMPLATE VM (fedora-39-xfce)
Add repo and install ivpn-ui. Shutdown.
DO NOT RUN IVPN INSIDE THE TEMPLATE

CREATE appVM (vpn-i-usa)
Launch a terminal in the VM, and make IVPN directories permanent:

sudo mkdir /rw/config/qubes-bind-dirs.d
sudo echo -e "binds+=( '/opt/ivpn' )\nbinds+=( '/etc/opt/ivpn' )" > /rw/config/qubes-bind-dirs.d/50_user.conf

Then follow the rest of this guide, inside the appVM. Your changes will persist across reboots.

Now you can backup your VPN VMs and save a few gigas ondisk. Much thanks to @solene , this is exactly the guide I was looking for. No chance I could’ve come up with all those nftables myself.

2 Likes

if I embedded the second command, I get an error message. Premission denied.

Try this:

echo -e "binds+=( '/opt/ivpn' )\nbinds+=( '/etc/opt/ivpn' )" | sudo tee /rw/config/qubes-bind-dirs.d/50_user.conf >/dev/null

It worked, thanks for the quick help. I will now do the mullvad guide. Do you know which binds I have to use? Mullvad VPN 4.2
@apparatus

And big thanks to @solene for the easy guide, it works like a charm. Can I trust this with my life?

For that guide you don’t have to use any binds because this guide is using StandaloneVM instead of AppVM for sys-vpn.
I don’t know what binds to configure for the AppVM usage.

I have a quick question, if I have Qubes VPN based on fedora38, I should switch to the new version 40 normally from the terminal, like this :
sudo dnf system-upgrade download --releasever=40
sudo dnf system-upgrade reboot

but is there any difference if it’s quebes standalone?