Introduction
This guide is for users who want to let a qube access some specific websites, but not the entire Internet. It’s especially useful when using the Qubes firewall isn’t enough — for example, when websites change their IPs often, making domain-based rules unreliable.
This guide assumes you know what an HTTP(S) proxy is, and that you’re comfortable using the terminal to run commands or edit files.
The setup will create a sys-proxy-out
qube that filters access to a list of allowed domains. It uses qvm-connect-tcp
so that other qubes can use this proxy, even if they don’t have a NetVM. That way, those qubes can reach only the websites you’ve allowed — nothing more.
I based it on debian 12 xfce, so it’s easy to set up and will be supported long term.
Use case
- an offline qube that need to reach a particular website
- a web browsing qube restricted to a list of websites
- mix multiple netvm / VPNs into a single qube
Setup the template
- Install debian-12-xfce template
- Make a clone of it, let’s call it debian-12-xfce-squid
- Start the qube and open a terminal
- Type
sudo apt install -y squid
- Type
sudo systemctl disable squid
- Delete and replace
/etc/squid/squid.conf
with this content (the default file is not suitable at all)
acl localnet src 127.0.0.1/32
acl SSL_ports port 443
acl Safe_ports port 80
acl Safe_ports port 443
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
acl permit_list dstdomain '/rw/config/domains.txt'
http_access allow localnet permit_list
http_port 3128
cache deny all
logfile_rotate 0
coredump_dir /var/spool/squid
The configuration file only allows the proxy to be used for ports 80 and 443, and disables cache (which would only apply to port 80).
Close the template, you are done with it.
Setup an out proxy qube
This step could be repeated multiple times, if you want to have multiple proxies with different lists of domains.
- Create a new qube, let’s call it
sys-proxy-out
, based on the template you configured above (debian-12-xfce-squid
in the example) - Configure its firewall to allow the destination
*
and port TCP 443, and also*
and port TCP 80 (this covers basic needs for doing http/https). This is an extra safety to be sure the proxy will not use another port. - Start the qube
- Configure the domain list in
/rw/config/domains.txt
with this format:
# for a single domain
domain.example
# for all direct subdomains of qubes.org including qubes.org
# this work for doc.qubes-os.org for instance, but not foo.doc.qubes-os.org
.qubes-os.org
When you change the file with the domain list, you need to reload squid with
sudo systemctl reload squid
.
If you want to check squid started correctly, type
systemctl status squid
. You should read that it’s active, and that there are no error in the log lines.
If you have a line with a domain included by another line, squid will not start as it considers it an error! For instance
.qubes.org
includes doc.qubes-os.org
.
As far as I know, it is only possible to allow a hostname or a wildcard of this hostname, so you at least need to know the depth of the hostname. If you want to allow
anything.anylevel.domain.com
, you could use dstdom_regex
instead of dstdomain
, but it seems a regular source of configuration problems, and should not be useful for most users.
In dom0, using the “Qubes Policy Editor” GUI, create a new file 50-squid
(or edit the file /etc/qubes/policy.d/50-squid.policy
) and append the configuration lines that you need to adapt from the following example:
qubes.ConnectTCP +3128 MyQube @default allow target=sys-proxy-out
qubes.ConnectTCP +3128 MyQube2 @default allow target=sys-proxy-out
This will allow qubes MyQube
and MyQube2
to use the proxy from sys-proxy-out
. Adapt to your needs here.
How to use the proxy
Now the proxy is set up, and MyQube
is allowed to use it, a few more things are required:
- Start qube
MyQube
- Edit
/rw/config/rc.local
to addqvm-connect-tcp ::3128
- Configure http(s) clients to use
localhost:3128
as a proxy
It’s possible to define the proxy user wide, this should be picked by all running programs, using this:
mkdir -p /home/user/.config/environment.d/
cat <<EOF >/home/user/.config/environment.d/proxy.conf
all_proxy=http://127.0.0.1:3128/
EOF
Congratulations on reaching this line!
Going further
Using a disposable qube for the proxy
The sys-proxy-out could be a disposable. In order to proceed:
- mark sys-proxy-out as a disposable template in its settings
- create a new disposable qube using sys-proxy-out as a template
- adapt the dom0 rule to have the new disposable qube name in the target field
Checking logs
In the proxy qube, you can check all requests done in /var/log/squid/access.log
, you can filter with grep TCP_DENIED
to see denied requests, this can be useful to adapt the domain list.
Test the proxy
Check allowed domains are reachable
From the http(s) client qube, you can try this command to see if the proxy is working:
curl -x http://localhost:3128 https://a_domain_you_allowed/
If the output is not curl: (56) CONNECT tunnel failed, response 403
then it’s working.
Check non-allowed domains are denied
Use the same command as above, but with a domain you did not allow
curl -x http://localhost:3128 https://a_domain_you_allowed/
The output should be curl: (56) CONNECT tunnel failed, response 403
.
Verify nothing is getting cached
In the qube sys-proxy-out
, inspect /var/spool/squid/
, it should be empty. If not, please report here, this should not happen.
Some logs file exist in /var/log/squid/
, if you don’t want any hints about queried domains, configure squid accordingly. Privacy-specific tweaks are beyond the scope of this guide.