App qube bricked by custom rules in rc.local

I have an app qube that I want to always be offline, I am using a Whonix Workstation based template so that timezones, hostnames, etc, are anonymized.

It does not have a NetVM, but to prevent accidents I added these rules in rc.local

nft flush ruleset
nft add table inet drop-all
nft add chain inet drop-all output '{ type filter hook output priority 0; policy drop; }'
nft add rule inet drop-all output counter reject
nft add chain inet drop-all input '{ type filter hook input priority 0; policy drop; }'
nft add rule inet drop-all input counter reject
nft add chain inet drop-all forward '{ type filter hook forward priority 0; policy drop; }'
nft add rule inet drop-all forward counter reject

After restarting the app qube is bricked, and is unable to respond to anything.

What could I do instead within the app qube to modify the firewall to reject any traffic?

This is mostly a Qubes question. Any recovery method that could be used for Qubes, could most likely also be used for Qubes-Whonix.

The issue is unspecific to Whonix.

See also:

(Whonix is based on Kicksecure.)

I wrote down some ideas here:
Non-Bootable Qubes VM

But then thanks to I found a rather simple idea.

You could probably edit /usr/lib/qubes/init/ in Template and temporarily disable processing of /rw/rc.local.

Yes, this is true. Sorry, I should have been more clear. I am asking more specifically about advice to change the firewall. It is possible to limit the outgoing IP addresses to using documented methods in the wiki. Would you recommend that? Or perhaps a different place to put my firewall rules?

Furthermore, here is a great link to include in that page for data recovery from a bricked app qube.

The firewall is designed in a way that for most users no modifications are required. Only needed for very special use cases.

Adding additional firewall rules is documented here:
Whonix-Workstation Firewall settings: Additional User Custom Firewall Rules

No, I don’t know any reason why that would be useful.

Common questions are documented in the wiki:

There are also example settings files in /etc/whonix_firewall.d to tweak some settings.

Beyond that there aren’t even any popular feature requests coming to mind.

I understand, I changed it to a user level systemd unit that runs after Whonix firewall. My rules are applied now without bricking the app qube.

If I were to phrase this as a feature request it would be “offline mode for Whonix firewall”.

Of course, the best option is to not install qubes-core-agent-networking and to not assign a NetVM. But in this case I’m not modifying a template and only want to prevent accidents if a NetVM were to be assigned.

Many options to accomplish that come to mind. All untested.

You could disable the whonix-firewall using systemd.

And then implement your own firewall.

A systemd drop-in config snippet for whonix-firewall.service which disables it.


An /etc/whonix_firewall.d configuration snippet perhaps. These are just parsed as bash scripts. Run your script from it. Then exit 0 to stop further execution of whonix-firewall. Not the cleanest solution but seems easy.

Sounds like a good solution to me. It doesn’t clear the qubes table, but I suppose that doesn’t matter.

# run as root, reboot after first run then run again for settings to apply

# make /etc/whonix_firewall.d/ persistent
mkdir -p /rw/config/qubes-bind-dirs.d
touch /rw/config/qubes-bind-dirs.d/50_user.conf
echo "binds+=( '/etc/whonix_firewall.d/' )" > /rw/config/qubes-bind-dirs.d/50_user.conf

# write rules to user firewall conf
cat > '/etc/whonix_firewall.d/50_user.conf' << EOF
/usr/sbin/nft flush ruleset
/usr/sbin/nft add table inet reject-all

# uncomment line below to brick app qube
#/usr/sbin/nft add chain inet reject-all output '{ type filter hook output priority 0; policy drop; }'
exit 0

Unless you feel it’s important, you don’t need to waste your time debugging this. But I am a bit perplexed.

This script makes /etc/whonix_firewall.d/ persistent, then writes firewall rules to 50_user.conf. It requires a reboot to make the settings persist, on the second reboot after running it again the custom rules will load.

Adding my chain bricks the app qube however. Is there anything that sticks out to you as wrong?

I forgot to consider Qubes App VM persistence while writing my previous post.

So to avoid the bind-dirs complexity, just use this folder: