URL filtering HTTPS proxy

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.

:warning: 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

:information_source: When you change the file with the domain list, you need to reload squid with sudo systemctl reload squid.

:information_source: 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.

:warning: 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.

:warning: 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. :+1:

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 add qvm-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_not_listed/

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.

10 Likes

hi Solene, im configuring it following your guide.
when you said " * Create a new qube based on the template you configured above" with “new qube” do you mean sys-proxy-out? in this case please can you update the guide with the note like " * Create a new qube based (e.g sys-proxy-out) on the template you configured above" so will be more clear for noobie.
thank you so much!
best regards

Sure, this is a good enhancement suggestion!

1 Like

Hi @solene,
I see that after this command, squid does not start automatically (saw from systemctl status squid) if you don’t reboot the Appvm. Or maybe instead of reboot you need to do " sudo systemctl start squid from console? please can you update guide accordling?

Anyway, i complete all guide and squid working:)

thanks so much, best regards

1 Like

Thank you for this guide! It was just what I needed to allow an offline qube to reach a single subdomain.

And a suggestion:

Maybe mention that the qubes-policy-editor-gui can be used to edit the policy? E.g.

qubes-policy-editor-gui 50-squid

This would have the advantage of an integrated help and syntax check.

1 Like

This is a great idea, I never used this command, this is a good opportunity to introduce it to users.

1 Like

I thought about it, the thing is that when you start the sys-proxy-out qube the first time there is no domain list (hence why it’s disabled in the template).

Actually, now I’m answering, it may be better to not disable it in the template, and just tell users to reload if they make changes :thinking:

Great! I tested it twice before publishing. I always make sure it will work.

Cool, squid can be enabled in the template, it starts even if the domains.txt file is absent, and reloading squid in an appvm works fine without having to think about starting / restarting it.

Hi @solene ,
i have a few Qubes lets say Qube1, Qube2, Qube3, and Quebe4. Some (let’s say 1 and 2) need to navigate via Squid so sys-proxy-out with standard netvm sys-firewall, others (let’s say 3 and 4) need to also navigate via Squid so sys-proxy-out but going via VPN (sys-vpn) so netvm is sys-vpn.
In this case make sense to “duplicate” squid cube and so create other one let’s say sys-proxy-out-vpn? if no, why? if yes, i can keep port 3128 too?
thank you

You need to duplicate sys-proxy-out with a different netvm and different domains, that’s why I used a template enabling squid, so a new squid proxy is just a new qube with a domain list to create.

1 Like

@solene ok great thanks Solene! :slight_smile: but you can confirm that i need i need to setup new squid proxy with other listening port e.g 3129? otherwise the client cube how it know to which one need to connect?
so from qube side i will set localhost:3128 for sys-proxy-out and let’s say localhost:3129
for sys-proxy-out-VPN right? in 50-squid.policy i can have:
qubes.ConnectTCP +3128 MyQube @default allow target=sys-proxy-out
qubes.ConnectTCP +3129 MyQube @default allow target=sys-proxy-out-vpn
?
can you so be kind to help me with dns topic ? i would like to know how you manage DNS. see the new topic opened (How do you manage DNS topic?). a guide would be very useful for all community.
thanks so much

How would that work?

It’s quite easy, you can have multiple out proxies using their own netvm, and allow each of them into a single qube, using a different port for each to use their proxy.

This would allow to run a program A with proxy A, program B with proxy B etc… If you make the multiple proxies available to the qube, it’s up to you to choose which program use which proxy.

1 Like

Ah interesting. Thank you for the explanation!

Nice thing.
I was considering installing Safing Portmaster in every non vpn’ed qube because firewall work with IP and not domains.
But now there is a solution.

That’s a great product but as it runs on the same system as the software in the qube, it’s not as good as an out proxy. Although, really, Safing portmaster is good :sunglasses:

I’m using it with YT qube as YT use many servers around the world, each for different part of service.

This section appears to be a repeat of the “Check allowed domains are reachable”.

Thanks for reporting this, I fixed it.

1 Like

I saw that not all apps catch all_proxy variable. E.g rclone want http_proxy and https_proxy direct variable.