negative zero

VPN Killswitch with UFW

2021 March 23

[tech] [tutorial] [vpn]

Updated 2021 November 13 to fix a code issue.

I've written about Virtual Private Networks (VPNs) before:

As I've argued before, VPNs as a privacy tool are mostly hype that addresses obsolete security issues and shifts trust from one ISP to another, rather than providing a strong form of anonymity. I don't think they're useless, but I think you should understand how they work and what benefits they do and don't provide for you. I don't recommend paying for a VPN subscription just because you saw an ad that told you it would protect you from hackers.

Supposing you are using a VPN to proxy your traffic for privacy, you should set up a killswitch. If your VPN fails, you may fall back to connecting directly to the destination, allowing it to see your IP address and allowing your ISP to see that you are connecting to that destination. A killswitch blocks all traffic if your VPN drops, preventing this issue.

Uncomplicated Firewall (UFW) is what it sounds like. We will be using it to set up the killswitch. This guide assumes you're running GNU/Linux and have root access through sudo. It also assumes you have /usr/local/bin in your PATH. This method does not require you to know the IP address of your VPN server, which is nice because that may change each time you connect. Unfortunately, if your VPN fails, you will not be able to reconnect without first disabling the killswitch.

1. Install UFW

The ufw package is probably available through your package manager.

2. Connect to your VPN

You must connect to the VPN before enabling the killswitch. This will vary some by distribution. Likely, you have NetworkManager available and can use it to set up a VPN connection using configuration files from your VPN provider.

I will assume here that the VPN is running on the tun0 interface. You can run:

ip link show

to see your network interfaces if you aren't sure.

3. Set UFW rules

Now that we have a VPN connection on tun0 (replace tun0 with your interface if applicable), we'll set UFW rules to allow traffic through only the VPN tunnel. We'll run the following commands:

sudo ufw reset

sudo ufw default deny incoming

sudo ufw default deny outgoing

These instructions tell our firewall not to allow any traffic. Now we need to allow VPN connections.

sudo ufw allow out on tun0 from any to any

(Replace tun0 with your VPN interface.) This says, "Allow any outgoing connections over the established VPN tunnel."

(Outgoing means that you initiate the connection by sending a message to the server. Once this connection has been established, the server can respond. Unless you're running a server, you probably don't need to and should not accept incoming connections.)

If you also need to allow incoming connections, also use a command like

sudo ufw allow in on tun0 from any to any

We'll allow connections on the local network as well. Also run the line:

sudo ufw allow out to

Here, I've assumed local IP addresses start with 192.168.1. If you have a different local subnet, adapt this line accordingly. Again, we're only allowing outgoing connections here.

Finally, enable UFW:

sudo ufw enable

4. Disable IPv6

IPv6 causes problems for many VPN configurations. Your VPN provider may have specific instructions for IPv6, which you may want to follow instead of disabling IPv6 altogether. As a generic safe step, we will disable IPv6 so that all of our traffic is IPv4 over the VPN tunnel.

sudo sysctl net.ipv6.conf.all.disable_ipv6=1

sudo sysctl net.ipv6.conf.default.disable_ipv6=1

sudo sysctl net.ipv6.conf.lo.disable_ipv6=1

Disabling the killswitch

To disable the killswitch, we'll provide new UFW rules. Below are standard rules for a normal user, which allow all outgoing connections and deny incoming connections. You may need different rules.

sudo ufw reset

sudo ufw default deny incoming

sudo ufw default allow outgoing

sudo ufw enable

Re-enabling IPv6

sudo sysctl net.ipv6.conf.all.disable_ipv6=0

sudo sysctl net.ipv6.conf.default.disable_ipv6=0

sudo sysctl net.ipv6.conf.lo.disable_ipv6=0

Automating it


To make this easier, we'll make a script which enables the killswitch and disables IPv6. Open a file at /usr/local/bin/killswitch-enable. I'll use nano for this:

sudo nano /usr/local/bin/killswitch-enable

Paste in this code:


ufw reset
ufw default deny incoming
ufw default deny outgoing
ufw allow out on tun0 from any to any
ufw allow out to
ufw enable

sysctl net.ipv6.conf.all.disable_ipv6=1
sysctl net.ipv6.conf.default.disable_ipv6=1
sysctl net.ipv6.conf.lo.disable_ipv6=1

Again, replace tun0 and the local subnet if applicable.

Save the file (in nano, Ctrl+s) and exit (in nano, Ctrl+x).

Now, we need to make the file executable.

sudo chmod +x /usr/local/bin/killswitch-enable


Now, we'll make a script which disables the killswitch and enables IPv6. Open a file at /usr/local/bin/killswitch-disable. Again, I'll use nano:

sudo nano /usr/local/bin/killswitch-disable

Paste in this code:


ufw reset
ufw default deny incoming
ufw default allow outgoing
ufw enable

sysctl net.ipv6.conf.all.disable_ipv6=0
sysctl net.ipv6.conf.default.disable_ipv6=0
sysctl net.ipv6.conf.lo.disable_ipv6=0

Save the file (in nano, Ctrl+s) and exit (in nano, Ctrl+x).

Now, we need to make the file executable.

sudo chmod +x /usr/local/bin/killswitch-disable

Using it

Now, after you connect to your VPN, you can run:

sudo killswitch-enable

After you disconnect from your VPN, run:

sudo killswitch-disable

Note that both of these scripts must be run as root.

One thing to know is that if your VPN disconnects, your killswitch will prevent it from reconnecting (because that would require traffic outside the VPN tunnel). In this event, make sure to stop all processes that will cause network traffic you don't want outside your VPN. Then, disable the killswitch, reconnect to your VPN, and enable the killswitch again.