Qubes OS Tor Configuration (Very Helpful When Using WebTunnel)
2025-07-27T21:01:46+08:00
Scenario – Whonix is not offering a complete Tor solution
As a security-focused operating system, Qubes OS has Whonix integrated into it, offering Tor connection support. However, since lyrebird
is still unavailable in Debian’s official repository, Whonix does not support WebTunnel bridges.
Unfortunately, in some countries obfs4 bridges are unusable, as the network is heavily censored. Using WebTunnel bridges may be the only option. Therefore, we can make use of the latest version of Tor, offering other qubes a NetVM that enables Tor access.
Step 1: Prepare a qube for the Tor daemon
In this step, we prepare a qube where the Tor daemon resides. Create a qube — here we create it as a StandaloneVM named tor-daemon
from the fedora-41-xfce
template. Enable autostart. Open a terminal in it after creation.
Install Tor:
$ sudo dnf install tor
Compile or download lyrebird
, place it in /usr/local/bin
, then:
$ sudo chown root\:root /usr/local/bin/lyrebird
$ sudo chmod +x /usr/local/bin/lyrebird
$ sudo ln -s /usr/local/bin/lyrebird /usr/bin/lyrebird
$ sudo semanage fcontext -a -t tor\_exec\_t '/usr/local/bin/lyrebird'
$ sudo restorecon -v /usr/local/bin/lyrebird
After that, configure your /etc/tor/torrc
. You may wish to add the following lines:
UseBridges 1
ClientTransportPlugin webtunnel exec /usr/local/bin/lyrebird managed
Bridge webtunnel ...
Bridge webtunnel ...
...
managed
is crucial, as it ensures that the Tor daemon and lyrebird
can be enabled by systemd.
Then, enable and start the Tor daemon:
$ sudo systemctl enable --now tor
Verify that it works:
$ torsocks curl myip.wtf
If an IP address is shown, it works. Proceed to the next step.
Step 2: Prepare a qube for routing
Clone the fedora-41-xfce
template. I proceeded with this template, but you may choose fedora-41-minimal
to save disk space — though I cannot confirm whether it works. Here we name the clone fedora-41-pt
.
After cloning the template, temporarily connect it to a network (e.g. sys-firewall
), then open a terminal and run:
$ sudo dnf install qubes-core-agent-networking iproute clash-meta dnscrypt-proxy torsocks
$ sudo systemctl disable dnscrypt-proxy
Then power it off and disconnect the template from the network.
Create an AppVM using the template we just created. Name it sys-tor
. Enable autostart for this qube as well. Then, in a terminal in dom0
, run:
$ sudo -s
# echo sys-tor @default allow,target=tor-daemon >> /etc/qubes-rpc/policy/qubes.ConnectTCP
# exit
$ qvm-firewall sys-tor del --rule-no 0
$ qvm-firewall sys-tor add drop
$ qvm-firewall sys-tor add --before 0 drop proto=icmp
$ qvm-firewall sys-tor add --before 0 drop specialtarget=dns
Then, open a terminal in sys-tor
. Create the directories /rw/proxy/dns
and /rw/proxy/clash
.
Open /rw/proxy/dns/dnscrypt-proxy.toml
and add:
listen_addresses = ['127.0.0.1:5353']
max_clients = 250
proxy = 'socks5://127.0.0.1:7891'
timeout = 5000
keepalive = 30
ignore_system_dns = true
netprobe_timeout = 0
cache = true
[static]
[static.quad9_doh]
stamp = 'sdns://AgMAAAAAAAAABzkuOS45LjkgKhX11qy258CQGt5Ou8dDsszUiQMrRuFkLwaTaDABJYoSZG5zOS5xdWFkOS5uZXQ6NDQzCi9kbnMtcXVlcnk'
[static.mullvad_doh]
stamp = 'sdns://AgcAAAAAAAAAAAAPZG9oLm11bGx2YWQubmV0Ci9kbnMtcXVlcnk'
Open /rw/proxy/clash/config.yaml
and add:
socks-port: 7891
redir-port: 7892
mode: rule
allow-lan: true
bind-address: '*'
dns:
enable: false
proxies:
- name: "socks_proxy"
type: socks5
server: 127.0.0.1
port: 9050
rules:
- MATCH,socks_proxy
Open /rw/config/rc.local
and add:
qvm-connect-tcp 9050:@default:9050
sysctl -w net.ipv4.conf.all.route_localnet=1
nft 'add rule ip qubes custom-forward oifname "eth0" drop'
nft 'add rule ip6 qubes custom-forward oifname "eth0" drop'
nft 'add rule ip qubes custom-forward iifname "eth0" drop'
nft 'add rule ip6 qubes custom-forward iifname "eth0" drop'
nft flush chain ip qubes dnat-dns
nft 'add rule ip qubes dnat-dns ip daddr 10.139.1.1 udp dport 53 dnat to 127.0.0.1:5353'
nft 'add rule ip qubes dnat-dns ip daddr 10.139.1.1 tcp dport 53 dnat to 127.0.0.1:5353'
nft 'add rule ip qubes dnat-dns ip daddr 10.139.1.2 udp dport 53 dnat to 127.0.0.1:5353'
nft 'add rule ip qubes dnat-dns ip daddr 10.139.1.2 tcp dport 53 dnat to 127.0.0.1:5353'
nft 'add rule ip qubes custom-input iifname "vif*" tcp dport 7892 accept'
nft 'add rule ip qubes custom-input iifname "vif*" udp dport 7892 accept'
nft 'add rule ip qubes custom-input iifname "vif*" tcp dport 5353 accept'
nft 'add rule ip qubes custom-input iifname "vif*" udp dport 5353 accept'
nft 'add chain ip qubes redir { type nat hook prerouting priority -99 ; policy accept; }'
nft 'add rule ip qubes redir iifname "vif*" ip protocol udp redirect to :7892'
nft 'add rule ip qubes redir iifname "vif*" ip protocol tcp redirect to :7892'
nft 'add chain ip qubes output { type filter hook output priority filter ; policy drop; }'
nft 'add rule ip qubes output ct state related,established accept'
nft 'add rule ip qubes output oifname "lo" accept'
nft 'add rule ip qubes output ip daddr 127.0.0.1 accept'
clash-meta -d /rw/proxy/clash >/dev/null 2>&1 &
sleep 0.5
dnscrypt-proxy -config /rw/proxy/dns/dnscrypt-proxy.toml >/dev/null 2>&1 &
Download this file (proprietary licence, but it is not actually used; I will try with a random file later) to /rw/proxy/clash/Country.mmdb
.
Restart sys-tor
.
Step 3: Connect to the Tor network
Choose the qube from which you want to connect to the Tor network. Set its NetVM to sys-tor
.
Open a browser and navigate to this website. If it shows You are using Tor!
— voilà!
If not, check your configuration and consult the community.
If you encounter an OCSP problem, disabling OCSP querying in the browser settings is a workaround, though I currently do not have a proper solution.
By the way, you can also try rebooting your machine to ensure the configuration persists after reboot.