Setting up Xray VPN with DNSCrypt in QubesOS

May 24, 2025

This guide will walk you through setting up a secure VPN connection using Xray in QubesOS, combined with DNS encryption and authentication using dnscrypt-proxy. This setup provides both privacy and security for your network traffic.

Prerequisites

Step 1: Create and Configure the Template

First, we need to create a Debian-based template for our VPN qube:

# Clone the Debian template
qvm-clone debian-12-xfce sys-vpn-template

# Create the VPN AppVM called sys-vpn
qvm-create --template sys-vpn-template --label red sys-vpn

Step 2: Configure the Template VM

In the template VM, we’ll install and configure the necessary components:

# Install required packages
sudo apt install redsocks curl wget -y

# Enable redsocks service
sudo systemctl enable redsocks

# Configure redsocks to listen on all interfaces 
sudo sed -i '1,/local_ip = 127.0.0.1/s/local_ip = 127.0.0.1/local_ip = 0.0.0.0/' /etc/redsocks.conf

# Enable IP forwarding
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/50-ipforward.conf
echo 'net.ipv4.conf.all.route_localnet=1' | sudo tee /etc/sysctl.d/50-routelocalnet.conf

DNS Setup

We’ll use dnscrypt-proxy with a blocklist (Hagezi Pro+) to block ads/trackers/etc:

# Switch to root
sudo su
# Enable networking
export HTTP_PROXY=http://127.0.0.1:8082
export HTTPS_PROXY=http://127.0.0.1:8082
echo "http_proxy=http://127.0.0.1:8082" >> /etc/wgetrc
echo "https_proxy=http://127.0.0.1:8082" >> /etc/wgetrc

# Run installer
curl https://raw.githubusercontent.com/svobodacenter/rpi-ap-proxy/refs/heads/master/install-dnscrypt.sh | bash

# Disable networking
sed -i '/http_proxy=http:\/\/127.0.0.1:8082/d' /etc/wgetrc
sed -i '/https_proxy=http:\/\/127.0.0.1:8082/d' /etc/wgetrc

# Set correct port for dnscrypt-proxy
sed -i 's/53535/5353/' /etc/dnscrypt-proxy/dnscrypt-proxy.toml
systemctl restart dnscrypt-proxy

Create a dedicated user for Xray:

sudo useradd -M -r -s /usr/sbin/nologin xray

Step 3: Configure the VPN AppVM

In the sys-vpn VM, we’ll set up Xray and configure the networking rules.

Install Xray

sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -u xray

Configure Firewall Rules

Edit /rw/config/rc.local with the following content:

#!/bin/bash

# DNS FIREWALL SETTINGS
sudo nft flush chain ip qubes dnat-dns
sudo nft add rule ip qubes custom-input iifname "vif*" tcp dport 5353 accept
sudo nft add rule ip qubes custom-input iifname "vif*" udp dport 5353 accept
sudo nft add rule ip qubes dnat-dns iifname "vif*" ip daddr 10.139.1.1 udp dport 53 dnat to 127.0.0.1:5353
sudo nft add rule ip qubes dnat-dns iifname "vif*" ip daddr 10.139.1.1 tcp dport 53 dnat to 127.0.0.1:5353
sudo nft add rule ip qubes dnat-dns iifname "vif*" ip daddr 10.139.1.2 udp dport 53 dnat to 127.0.0.1:5353
sudo nft add rule ip qubes dnat-dns iifname "vif*" ip daddr 10.139.1.2 tcp dport 53 dnat to 127.0.0.1:5353

# PROXY FIREWALL SETTINGS
sudo nft add rule ip qubes custom-input iifname "vif*" tcp dport 12345 accept
sudo nft add rule ip qubes custom-input iifname "vif*" udp dport 12345 accept
sudo nft add chain ip qubes redir '{ type nat hook prerouting priority -99 ; policy accept ; }'
sudo nft add rule ip qubes redir iifname "vif*" ip protocol udp redirect to :12345
sudo nft add rule ip qubes redir iifname "vif*" ip protocol tcp redirect to :12345

# START XRAY
xray --config /home/user/config.json &

Xray Configuration

Create /home/user/config.json with the following configuration (replace YOUR_VPN_DOMAIN and YOUR_USER_ID with your actual values). VLESS protocol is used for VPN connectivity:

{
	"log": {
		"loglevel": "debug"
	},
	"routing": {
		"domainStrategy": "AsIs",
		"rules": [
			{
				"type": "field",
				"source": ["127.0.0.1"],
				"ip": ["10.139.1.1", "10.139.1.2"],
				"network": "udp,tcp",
				"outboundTag": "dns-out"
			}
		]
	},
	"inbounds": [
		{
			"tag": "socks-in",
			"listen": "127.0.0.1",
			"port": 1080,
			"protocol": "socks",
			"settings": {
				"auth": "noauth",
				"udp": true
			},
			"sniffing": {
				"enabled": true,
				"destOverride": ["http", "tls"]
			}
		}
	],
	"outbounds": [
		{
			"tag": "proxy",
			"protocol": "vless",
			"settings": {
				"vnext": [
					{
						"address": "YOUR_VPN_DOMAIN",
						"port": 443,
						"users": [
							{
								"id": "YOUR_USER_ID",
								"flow": "xtls-rprx-vision-udp443",
								"encryption": "none"
							}
						]
					}
				]
			},
			"streamSettings": {
				"network": "tcp",
				"security": "tls",
				"tlsSettings": {
					"allowInsecure": false,
					"fingerprint": "firefox"
				}
			}
		},
		{
			"protocol": "freedom",
			"tag": "direct"
		},
		{
			"protocol": "blackhole",
			"tag": "block"
		},
		{
			"protocol": "freedom",
			"settings": {
				"redirect": "127.0.0.1:5353"
			},
			"tag": "dns-out"
		}
	]
}

Usage

Now if you want some qube to be proxied through VPN, just set sys-vpn as NetVM of the qube.

Configuration Details

Troubleshooting

If you encounter issues:

  1. Check the Xray logs: journalctl -u xray
  2. Verify DNS resolution (in template VM): dig @127.0.0.1 -p 5353 example.com
  3. Check firewall rules: sudo nft list ruleset
If you want to support us, you can donate here: