I’ve started using ProtonVPN on my home Internet connection. With the ever increasing pressure on ISPs to share customer information to government agencies and copyright trolls, I felt more and more uncomfortable having this metadata accessible, and I figured it was now time to go the VPN route to at least shield my metadata from the ISP. I didn’t do this to obscure browsing metadata from websites or hide which country I’m in, though. I’m not that paranoid, yet.

Blocking Issues…

In the past, I didn’t configure a VPN on my internet connection (i.e. on the gateway, encrypting all traffic), because I foresaw two blocking issues:

  1. Speed
    I feared that a VPN would slow down speeds dramatically, to a point where it’s barely usable
  2. Latency-sensitive applications
    I host and attend a lot of webinars, online calls, etc. All of these are latency sensitive, and I feared that a VPN would increase the latency on those so much to a point where it wouldn’t be usable.
  3. Administrative overhead
    I didn’t want to add complexity that only I can manage (or requires my intervention when it breaks) to the home network.

The Solution

After some research, I concluded I could use a VPN for the entire home network, without running into these blocking issues.

The solution was simple, but three-fold:

  1. Select a performant VPN provider. I use ProtonVPN.
  2. Configure the pfSense gateway in a specific way to exclude only certain traffic
  3. Configure the pfSense to failback to regular Internet if the VPN disconnects.

So, I set out to find out how this would work in my specific setup, of which the major components are ProtonVPN (Plus) and my virtual pfSense router/gateway for my home connection.

Why ProtonVPN?

Choosing a VPN provider is hard. You have to dig deep to be able to trust a provider. Jurisdiction, technology, exit nodes and security all matter. And then it’s also about the service offered: is it fast enough, does it have good clients, support for 3rd party clients (like OpenVPN), does it have good documentation and support? I won’t go into all these, but I will share my conclusion: I chose ProtonVPN, as I think it’s secure based on where they’re based (Switzerland), what technology they use (OpenVPN) and how they are able to route your traffic (Secure Core). Also, I determined they reach near-ISP speeds (300/30 Mbit in my case), have good support for 3rd party OpenVPN clients (which I needed for pfSense), good documentation and a good reputation.

Which traffic to exclude?

With the major choices now made, I started thinking more concretely about which traffic I wanted to exclude. This would be a relative small list, all entries determined by either trust or latency sensitivity.

As an example, I excluded my co-located IaaS facility, where I run Ze Klauwd. I trust this destination (as I own and manage all aspects of the hardware and trust the ISP on the co-lo side). Excluding this traffic was really easy, as I know exactly (down to the IP-address) which traffic it is. Just a matter of entering the IP-range in the relevant pfSense configuration.

For other traffic, it’s more difficult. My employer uses Office 365, Azure Active Directory and other Microsoft cloud-based solutions. I want to exclude these, because there’s all kind of identity protection features in these services, the most important one being Impossible Travel. With a VPN, my traffic to these services could show up from different VPN exit nodes (in different countries), and I’d be locked out from using these services too often.

These services are, by design multi-tenant. Excluding these services from the VPN would exclude all traffic to Office 365, Azure and other Microsoft properties, even if they are distinct from the services I use for work. I had to decide if I am comfortable with this, not knowing which other traffic is excluded from the VPN because of the multi-tenant premise of these services. It could very well be that a highly privacy-sensitive website that I wouldn’t want to expose to my ISP is hosted on Microsoft Azure. With the current setup (i.e. pfSense) it would be very hard to distinguish between different logical tenants that are all hosted on the same service (as they are Layer 7 or even ‘8’), and pfSense isn’t great at application firewalling. I accepted this risk, and chose to route traffic based on IP-ranges, not on application level.

This poses a third problem with deciding which traffic to exclude: the dozen or so online conferencing and webinar solutions I use. Ranging from WebEx to appear.in and Slack calls, I use a lot of them. That includes Skype for Business I use for work (but is easily excluded from the VPN, as it’s hosted in a co-lo datacenter with fixed IP-ranges). Excluding all of these services from the VPN would be too cumbersome, and I didn’t want the manual administrative overhead of managing all those IP-ranges (which would inevitably change). I accepted the risk of these services not working too well over the VPN, with an option to temporarily disabling the VPN when latency was too bad to make these solutions usable.

A first test proved that a WebEx I did recently over the VPN works flawlessly, so I’m not too worried about this. In the end, I opted to exclude very little from the VPN (only the work estates in Office 365, Klauwd.com and the company Skype for Business service), and just see how it’s going to turn out. Just ask me on Twitter for status updates :-).

Anyway, configuring this is a bit of a task in pfSense, but using the excellent blogpost by Matya, it’s done in no time. Basically, using routing, manual outbound NAT rules and some firewall rules (based on aliases), it’s pretty straight-forward.

Add a new Interface

 Interfaces => (assign)

Here we create a new interface for our OpenVPN connection we set up earlier. On the “Available network ports” line pick the ovpncXinterface. This will create you an OPTX interface, depending on how many interfaces you already have.ProtonVPN_Interface_config

Click on its name to open and edit it. Make sure to choose a Description that will match your setup, since after you got it used by a Gateway, pfsense does not allow you to change it. I have chosen PROTONVPN. Make sure to check “Block bogon networks” but do not check to block private Addresses, since the VPN has a subnet of 10/8, which would be blocked otherwise.
Click here to see the whole page. After saving, you should see the new interface being show in the Interfaces drop down menu.

IP Aliases

Firewall => Aliases

I personally utilize the Aliases of pfsense, which comes handy to define destinations like WORK_VPN or YOUTUBE or NETFLIX, for which you can find IP subnets after some searching. Later I bundle them together in a DIRECT_ACCESS alias, which holds the separate entries, so I don’t have to touch the NAT Rules after editing this list.ProtonVPN_Aliases

NAT Rules

Firewall => NAT => Outbound

Here we need to change “Automatic outbound NAT rule generation” to “Manual Outbound NAT rule generation” to get the freedom to reorder and edit the entries, so they make sense.

I have for VOIP Telephony a Fritz!Box, which is in my DMZ, but it is latency-sensitive, and needs a direct port NAT-SIP protocol is not that big of a mess, so that goes on top.

I have created three additional NAT rules, that define how the translation will happen if the package arrives from my home network (it’s represented by the USG_DMZ alias). The remaining are the default rules for the outgoing WAN packets, which have been generated by the automatic rule generation.ProtonVPN_NAT_Outbound

Firewall rules

This is the most challenging part, since you need to design your network routes now. We have set up the proper VPN Gateway with monitoring and fallback to the WAN gateway, defined how the packages need to behave if they are sent out via the PROTONVPNinterface, now we only need to ensure the packages actually take the right interfaces on their path. Navigate to the proper interface where your Internet-facing traffic arrives to the pfsense box. For me, this is the DMZ interface, but for you it might be LAN.

Firewall => Rules => <Interface>

These rules are processed from top to bottom, and the first rule that applies is processed, and if none matches, default is to drop the package. In order to allow some dedicated traffic direct access bypassing our VPN Tunnel, we need first to create an entry that matches the destination we have defined in the DIRECT_ACCESS Alias. For the Source, you could choose LAN Net or the gateway your internet flows through, which in USG_DMZ for me. See here the whole config page

The next in the list should be a generic rule that catches all remaining traffic to go through the VPN gateway. To achieve this, we will need to open the Advanced options and scroll way down to Gateway, keeping everything else as it is. Here at Gateway you can choose either the PROTONVPN_VPNV4 for VPN-Only, or our Gateway Group called VPN for WAN fallback.ProtonVPN_Rule_VPN_GatewayThe whole settings page can be viewed here.

For all this to work, we need to make sure the ordering is correct, so first we add a specific rule, and below it on that catches all remaining traffic.


No VPN means no internet?

One of the other things I feared was the dependence on the VPN, specifically not being able to use the regular connection if the VPN was down. It needed to ‘just work’, even when I’m not at home to fix things. Again Matya has the solution, creating a Gateway Group in pfSense:

Depending on if you want to have more VPN tunnels set up to load-balance your traffic, or if you want your Internet not go black if the tunnel is down, you will need to create a Gateway Group. You can skip this part and pay attention at the Firewall rules if you want all your traffic to pass through the tunnel.
I have chosen my traffic to fallback to the default Gateway if the VPN is not available, so you have to add the PROTONVPN with Tier 1 and the WAN with Tier 2, and keep the rest unchanged.

We have created the Gateway called “VPN“, which uses the ProtonVPN Tunnel, but if that is not reachable, falls back to the default WAN route. This is good to have your wife not call you during the day if the VPN tunnel goes down for maintenance 🙂

Following the step-by-step

I’ve taken a few excerpts from Matya’s blog, and I highly recommend you read his entire article and follow the step-by-step if you want to configure ProtonVPN on pfSense yourself. All kudos for getting this to work go to Matya, not me.


Al this work setting up pfSense gives me an always-on VPN for my entire home network, which isn’t dependent on my break/fix skills when I’m not home to provide an Internet connection. It gives me peace of mind that my ISP no longer has insight into my traffic, and the flexibility to exclude traffic that isn’t suitable to traverse the VPN, such as latency-sensitive traffic (live audio / video) or high-bandwidth traffic (such as the Resilio Sync traffic that backs up important data on my NAS to the Klauwd.com colo).

Also, it’s easy to just disable the VPN for times that I don’t want to go through the hassle of configuring the firewall to exclude certain traffic, and just as easy to enable the VPN later. No other configuration is required when disabling or enabling the VPN.

Lastly, my Internet speed with the VPN on is more than decent. On my 300/30 Mbit connection, these are the speeds over the VPN: