Setting up Xray VPN with DNSCrypt in QubesOS
May 24, 2025This 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
- QubesOS installed
- Basic understanding of QubesOS networking
- A VPN server with Xray/VLESS configuration
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
- The setup uses Xray with VLESS protocol for VPN connectivity
- DNS traffic is protected using dnscrypt-proxy
- A blocklist is implemented to filter unwanted domains
- All traffic is routed through the VPN system VM
Troubleshooting
If you encounter issues:
- Check the Xray logs:
journalctl -u xray
- Verify DNS resolution (in template VM):
dig @127.0.0.1 -p 5353 example.com
- Check firewall rules:
sudo nft list ruleset