Introduction

Policy-Based Routing (PBR) lets you direct traffic from specific VLANs through a chosen WAN gateway — in this case, a WireGuard VPN tunnel — rather than following the default routing table. As a result, this approach is enormously powerful in a segmented home or office network: your IoT devices, guest VLAN, or privacy-sensitive clients all route through Proton VPN (Or any other WireGuardVPN peers) at the router level, without installing any client software on end devices.

In this guide, you will walk through the full configuration of Proton VPN's WireGuard protocol on pfSense 2.7.x. In addition to the core setup, the guide also covers:

  • Per-VLAN policy-based routing via WireGuard gateway
  • Dual-stack IPv4 + IPv6 (ULA-based) through the VPN tunnel
  • Manual NAT for both IPv4 and IPv6
  • DHCP-delivered DNS that prevents leaks
  • Scaling to multiple WireGuard tunnels for additional VLANs
⚠ NOTE: This guide assumes you already have pfSense 2.7.x or 2.8.x running, your VLANs are defined (with VLAN interfaces and DHCP servers configured), and you have a Proton VPN account with at least one WireGuard configuration key generated. The ULA IPv6 prefix shown in the IPv6 sections is already configured in the author's environment and should be substituted with your own.
The setup guide have been tested on pfSense 2.7.x and 2.8.x.

Step 1 — Generate a WireGuard Configuration from Proton VPN

First, sign in to your Proton account at account.protonvpn.com and navigate to Downloads → WireGuard configuration. When prompted, choose Platform: Router. Next, select the target server (or let Proton choose the fastest one) and download the .conf file.

Once you have the file, open it with any text editor. You will need the following values for the pfSense setup:

FieldWhat to look for
PrivateKeyYour unique private key — keep this secret
Address10.2.0.2/32 (your VPN tunnel IPv4 address)
Endpoint IPThe numeric IP address on the Endpoint = line (e.g. 79.127.184.216)
PublicKey (Peer)The server's public key under the [Peer] section

For reference, a standard Proton VPN WireGuard config for a router looks like this:

[Interface]
PrivateKey = <your-private-key>
Address    = 10.2.0.2/32
DNS        = 10.2.0.1

[Peer]
PublicKey  = <server-public-key>
Endpoint   = <server-ip>:51820
AllowedIPs = 0.0.0.0/0

Then, with help of this guide from mikaeldui user at Github, I edited it for IPv6:

Create or get the WireGuard configuration file

Step 2 — Install the WireGuard Package (If not already)

To begin, log in to your pfSense web interface (default: 192.168.1.1). Then navigate to System → Package Manager → Available Packages. Search for wireguard and click Install next to the WireGuard package. Wait for the installation to finish.

Afterward, go to System → Package Manager → Installed Packages and confirm that WireGuard appears in the list. Once confirmed, the VPN menu gains a new WireGuard entry, which you will use in the next step.


Step 3 — Create the WireGuard Tunnel

Now go to VPN → WireGuard → Tunnels and click Add Tunnel. Configure the tunnel with the following settings:

Create the WireGuard Tunnel
SettingValue
DescriptionProtonVPN_Work (or any descriptive label)
Listen Port<Left it empty>
Private KeyPaste the PrivateKey value from your downloaded .conf file
Public KeyAuto-generated — Based on the PrivateKey
Interface Address (IPv4)10.2.0.2/32
Interface Address (IPv6)2a07:b944::2:2/128  (add this for IPv6 dual-stack)
Edit the WireGuard Tunnel
Since I already added a ProtonVPN WireGuard tunnel previously, I have to use the next available address if needed, see following pictures and see the Step 11 — Scaling to Multiple VLAN Tunnels
Edit the WireGuard Tunnel 2

Click Save Tunnel when done.

⚠ NOTE: About the GUA address Expand / Collapse

Step 4 — Add the WireGuard Peer

Still on the Tunnels page, click Add Peer (or go to VPN → WireGuard → Peers → Add). Then enter the following:

SettingValue
TunnelSelect the tunnel created in Step 3
DescriptionServer name or location (e.g. USA#60)
Dynamic EndpointUncheck
EndpointIP address from the Endpoint = line in your .conf (numeric only, no port)
Port51820
Keep Alive25
Public KeyServer's PublicKey from the [Peer] section of your .conf file
Allowed IPs (IPv4)0.0.0.0/0
Allowed IPs (IPv6)::/0  (add for IPv6 dual-stack)
Add the WireGuard Peer

If you had not already done it, click Save Peer. Then go to the Settings tab, check Enable WireGuard, and click Save → Apply Changes.

Add the WireGuard Peer - Apply Changes.
✓ TIP: Setting Keep Alive to 25 seconds ensures the tunnel stays active through NAT devices. Without it, idle connections may drop.

Step 5 — Create the WireGuard Interface Assignment

Although the WireGuard package creates a virtual network interface (such as tun_wg3), it does not automatically assign it as a routable pfSense interface. Therefore, you need to assign it manually.

Navigate to Interfaces → Interface Assignments. In the Available network ports dropdown, select tun_wg3 and click Add. A new interface will appear — typically OPT1 or the next available OPT number. Click on that newly listed interface name to configure it.

Interface Assignments
SettingValue
EnableChecked
DescriptionProtonVPN (or similar)
IPv4 Configuration TypeStatic IPv4
IPv4 Address10.2.0.2 / 32
IPv6 Configuration TypeStatic IPv6
IPv6 Address2a07:b944::2:2 / 128
Create the WireGuard Interface Assignment

Click Save, then Apply Changes. For the rest of this guide, this interface will be OPT_VPN — substitute your actual interface name (e.g. OPT1) wherever you see it.


Step 6 — Add Gateways

IPv4 Gateway

Go to System → Routing → Gateways and click Add. Configure the IPv4 gateway as follows:

Add a Gateways
SettingValue
InterfaceOPT_VPN (your WireGuard interface)
Address FamilyIPv4
NameGW_PROTONVPN (descriptive name)
Gateway10.2.0.1
Edit the ipv4 Gateways

Next, click Display Advanced and check Use non-local gateway → Use non-local gateway through interface specific route. This step is critical — without it, pfSense refuses to route through the WireGuard tunnel, because 10.2.0.1 does not sit on a directly connected subnet. Finally, click Save and Apply Changes.

Displayed advanced Gateways settings
Use non-local gateway through interface specific route under gateway settings
Save and Apply Changes in the gateway settings

IPv6 Gateway

Click Add again to create a second gateway for IPv6:

SettingValue
InterfaceOPT_VPN
Address FamilyIPv6
NameGW_PROTONVPN_V6 (descriptive name)
Gateway2a07:b944::2:1
Edit the ipv6 Gateways

Again, click Display Advanced and check Use non-local gateway → Use non-local gateway through interface specific route. Then click Save and Apply Changes.

⚠ NOTE: Proton VPN provides two DNS/gateway addresses per tunnel: 10.2.0.1 and 10.2.0.2 for IPv4, and 2a07:b944::2:1 and 2a07:b944::2:2 for IPv6. The .1 addresses serve as gateway endpoints (for routing), while the .2 addresses serve as your tunnel client addresses. These values stay consistent across all Proton VPN servers.

Step 7 — Configure Manual Outbound NAT

By default, pfSense relies on automatic NAT rules. However, to properly control NAT for policy-based routing through the WireGuard tunnel, you need to switch to Manual Outbound NAT.

Navigate to Firewall → NAT → Outbound. Change the mode to Manual Outbound NAT rule generation and click Save Apply Changes.

Manual Outbound NAT rule generation

Disable the Auto-Created OPT → WAN Rules

After switching to manual mode, pfSense automatically generates a set of rules. Locate and disable (click the checkmark icon) the following two rules:

  • Auto created rule for ISAKMP — OPT_VPN to WAN
  • Auto created rule — OPT_VPN to WAN
Disable the Auto-Created OPT - WAN Rules

Edit the LAN → WAN Rules to Point to the VPN Interface

Next, find and edit (click the pencil icon) these two rules:

  • Auto created rule — LAN to WAN
  • Auto created rule for ISAKMP — LAN to WAN
Edit the LAN - WAN Rules
Edit the LAN - WAN Rules to Point to the VPN Interface

In both cases, change the Interface to OPT_VPN and the Address Family to IPv4. Then click Save and Apply Changes.

Add IPv6 Manual NAT Rules

This step is often overlooked, yet it is essential for a working dual-stack setup. You need to add outbound NAT rules for IPv6 traffic that routes through the WireGuard interface. Specifically, add the following rules:

  • Source: your VLAN IPv6 subnet (using your ULA prefix), Interface: OPT_VPN, Translation: Interface Address — for IPv6
  • Repeat for each VLAN subnet that will route through the VPN

Copy over the IPv4 Manual NAT Rules and edit to IPv6 NAT rules:

Copy over the IPv4 Manual NAT Rules and edit to IPv6 NAT rules
Edit the IPv6 Manual NAT Rules
⚠ NOTE: The IPv6 NAT rules mirror the IPv4 pattern: source is your internal VLAN's ULA IPv6 range, the interface is OPT_VPN, and the translation is the WAN interface. Without these rules, IPv6 traffic from your VLANs will not be masqueraded and will be dropped at the Proton VPN endpoint.

Here is the combination of IPv4 and IPv6 NAT rules looks like:

The combination of IPv4 and IPv6 NAT rules

Step 8 — Firewall Rules for Policy-Based Routing

This is where the policy-based routing part actually takes effect. Rather than changing the default route for all traffic — which would break devices on non-VPN VLANs — you instead add a gateway override to specific VLAN firewall rules.

Assign the VPN Gateway on the VLAN Allow Rule

Go to Firewall → Rules → [Your VLAN interface tab] and locate (or create) the default allow rule for that VLAN — typically named "Default allow VLAN to any rule" or similar.

Firewall Rules Page for the VLAN

Click the pencil icon to edit it. Scroll down and click Display Advanced, then find the Gateway field. Change it from Default (or blank) to GW_PROTONVPN (your IPv4 VPN gateway). Finally, click Save and Apply Changes.

Firewall Rule for display advanced settings
Select the GW under firewall rule

Handle the IPv6 Default Allow Rule (Similar Pattern)

On the same VLAN rules page, locate the Default allow VLAN IPv6 to any rule. At this point, you have two options:

  • Disable it entirely by clicking the checkmark (if you do not want IPv6 on this VLAN outside the VPN tunnel)
  • Edit it and assign GW_PROTONVPN_V6 as the gateway (to route IPv6 through the VPN as well — recommended for a leak-free dual-stack setup)
✓ TIP: Each VLAN you want to force through the VPN gets this treatment independently. VLANs whose rules do NOT have a VPN gateway set will continue using the normal WAN — this is the beauty of policy-based routing.

Step 9 — DNS Configuration (No-Leak Setup via DHCP)

Rather than configuring system-wide DNS to go through the VPN — which would affect all interfaces — this setup instead uses DHCP to push specific DNS servers directly to VLAN clients. As a result, DNS requests from those clients stay inside the VPN tunnel, and your setup avoids any DNS leaks.

DHCP Server — Push VPN DNS to VLAN Clients

Go to Services → DHCP Server → [Your VLAN interface]. Under Servers, configure the DNS servers as follows:

DNS SettingValue
DNS Server tunnel 1 (IPv4)10.2.0.1
DNS Server tunnel 2 (IPv4)10.3.0.1
DNS Server tunnel 1 (IPv6 — in DHCPv6)2a07:b944::2:1
DNS Server tunnel 2 (IPv6 — in DHCPv6)2a07:b944::3:1
DHCP DNS option for IPv4
DHCP DNS option for IPv6

These addresses are Proton VPN's internal DNS resolvers, which clients can only reach through the tunnel. Consequently, clients receive these via DHCP and use them for all DNS queries, which travel through the WireGuard tunnel and resolve on Proton's infrastructure — completely bypassing your ISP or internal DNS.

Allow DNS Access in VLAN Firewall Rules

For the DNS servers above to be reachable from the VLAN, you also need firewall rules that permit access to those addresses. Add rules on your VLAN interface to allow:

Add a allows rules for the in that particular network to allow to access to the Proton VPN IPs, add a rule on the top and then arrange as needed:

Add a firewall rule in the VLAN rules page
  • Action: Pass, Address Family: IPv4+IPv6, Protocol: Any, Destination: [Alias-a list of IPs].
Editing the firewall rules for allowing Pronto VPN GW & DNS.

For the reference, here is my list for VPN addresses, Since I am using multiple tunnel, I have include multiple addresses, but feel free to customize it for you need:

My ProtonVPN DNS list alias page.
⚠ NOTE: Do NOT configure pfSense's System → General Setup DNS servers to point to the Proton VPN DNS. That approach (used in the basic single-LAN guide) routes all of pfSense's own DNS through the VPN — but in a multi-VLAN, policy-routed environment, you want DNS routing to follow the same per-VLAN policy as regular traffic. The DHCP approach achieves this cleanly.

Step 10 — IPv6 ULA and Dual-Stack Notes

Your internal network already uses a ULA (Unique Local Address) IPv6 prefix for LAN/VLAN addressing — specifically the fd::/8 range on your pfSense interfaces. In addition to that, the WireGuard VPN attaches a separate global unicast IPv6 address (2a07:b944::2:2/128) to the tunnel interface.

The dual-stack IPv6 setup through Proton VPN's WireGuard follows the same conceptual structure as the IPv4 setup in all previous steps. Specifically:

  • Tunnel interface address: 2a07:b944::2:2/128
  • Gateway: 2a07:b944::2:1
  • Allowed IPs on peer: ::/0 (routes all IPv6 through the tunnel)
  • NAT6 rules: source = your VLAN ULA prefix, interface = OPT_VPN, translation = interface address
  • DHCPv6 DNS: 2a07:b944::2:1 and 2a07:b944::2:2
  • Firewall rules: assign GW_PROTONVPN_V6 as gateway on the VLAN IPv6 allow rule

Because your ULA IPv6 prefix already sits on your VLAN interfaces and DHCP handles IPv6 address assignment, you need no additional DNS or address configuration at the pfSense system level for the VPN side. Instead, the gateway and NAT rules handle everything automatically once the WireGuard tunnel comes up.

✓ TIP: Most of Proton VPN servers support IPv6 tunneling. The address 2a07:b944::2:2 is Proton's hard-coded VPN client IPv6 address used by their Linux client — it stays consistent across all servers. Using a GUA (Global Unicast Address) instead of a ULA ensures correct address selection priority per RFC 6724, meaning your traffic will actually prefer IPv6 when connecting to dual-stack sites.

Step 11 — Scaling to Multiple VLAN Tunnels

One of the most common questions when setting up policy-based routing is how to run multiple independent WireGuard tunnels for different VLANs — for example, routing one VLAN through a UK server and another through a US server.

Fortunately, Proton VPN's WireGuard implementation supports this cleanly. Each additional tunnel simply increments the IP address scheme by one:

Tunnel / VLANIPv4 Client  |  IPv4 GW/DNS  |  IPv6 Client  |  IPv6 GW/DNS
Tunnel 1 (first VLAN)10.2.0.2/32  |  10.2.0.1  |  2a07:b944::2:2/128  |  2a07:b944::2:1
Tunnel 2 (second VLAN)10.3.0.2/32  |  10.3.0.1  |  2a07:b944::3:2/128  |  2a07:b944::3:1
Tunnel 3 (third VLAN)10.4.0.2/32  |  10.4.0.1  |  2a07:b944::4:2/128  |  2a07:b944::4:1

For each additional tunnel, repeat Steps 3 through 9 using the incremented IP scheme above. Moreover, keep the following points in mind:

  • Each tunnel requires a separate WireGuard configuration file from Proton VPN (each file carries its own private/public key pair)
  • Each tunnel gets its own pfSense interface assignment (OPT2, OPT3, etc.)
  • Each tunnel gets its own IPv4 and IPv6 gateway entries
  • The VLAN firewall rules point to the specific gateway for that VLAN
  • Do NOT edit the Listen Port as 51820 for every tunnel, left as empty; we are setting up a server side, pfSense handles the demultiplexing automatically
✓ TIP: Each WireGuard configuration you download from Proton VPN carries a unique key pair and endpoint server. Therefore, download a separate config file for each tunnel/server you plan to use. The IP addressing (10.2.0.2, 10.3.0.2, etc.) is what differentiates the tunnels in pfSense.

Step 12 — Verification

After completing all the steps above, verify that traffic flows correctly through the VPN tunnel.

Check WireGuard Tunnel Status

First, go to VPN → WireGuard → Status. You should see the tunnel listed with a Latest Handshake timestamp that is recent (within the last few minutes). If no handshake has occurred, then the tunnel is not connected.

Check Gateway Status

Next, go to System → Routing → Gateways. Both GW_PROTONVPN (IPv4) and GW_PROTONVPN_V6 (IPv6) should show a green Online status. If either shows as Unknown or Down, refer to the troubleshooting section below.

Test from a Client on the VPN VLAN

From a device on the VLAN that you configured for VPN routing, visit a site like https://ipleak.net or Proton VPN's own IP check. The displayed IP should be the Proton VPN server's address, not your ISP's. Similarly, the DNS section should show Proton's DNS resolvers, not your ISP's.

Test IPv6

Finally, from the same client, visit test-ipv6.com. You should see an IPv6 address from Proton VPN's range (starting with 2a07:b944 or a similar Datacamp/Proton ASN prefix), not your ISP's IPv6 prefix.


Troubleshooting

Gateway Shows as Unknown or Offline After All Configuration

This is a common issue. By default, pfSense monitors gateways by sending ICMP pings to the gateway IP. However, WireGuard tunnels do not always respond to pings, so pfSense marks the gateway as offline even though the tunnel actually works.

To resolve this, go to System → Routing → Gateways and edit your VPN gateway (GW_PROTONVPN and/or GW_PROTONVPN_V6). Click Display Advanced, then check Disable Gateway Monitoring. After you save and apply changes, the gateway shows as Online and traffic routes through it correctly.

✓ TIP: Disabling gateway monitoring does not disable the gateway itself — it simply stops pfSense from marking it offline when pings to the gateway IP go unanswered. You can turn the GW monitor off and turn the back one later to check connections if needed. This is the recommended approach for WireGuard-based gateways.

Tunnel Connects But No Traffic Flows

First, check that the Allowed IPs on the peer includes 0.0.0.0/0 (and ::/0 for IPv6). Next, verify that the Manual Outbound NAT rules point the interface to OPT_VPN. Also confirm that the VLAN firewall rule carries the gateway override and that the non-local gateway option is active on the gateway config.

IPv6 Not Working Through the Tunnel

Start by ensuring you added ::/0 to the peer's Allowed IPs. Then verify that GW_PROTONVPN_V6 exists and shows as active. Next, check that the IPv6 Manual NAT rules cover your VLAN's ULA prefix, and confirm that the VLAN firewall IPv6 allow rule carries GW_PROTONVPN_V6 as its gateway. Finally, remember that IPv6 NAT rules must be added separately — they do not inherit from IPv4 rules.

DNS Leaks Detected

If a DNS leak test shows your ISP's DNS servers, then VLAN clients are not using the Proton DNS that DHCP pushed. First, check that the DHCP server for the VLAN lists 10.2.0.1/10.2.0.2 and 2a07:b944::2:1/2a07:b944::2:2 as DNS servers. Then ensure firewall rules let the VLAN reach those addresses on port 53. Finally, verify that no other DNS override exists that might redirect queries.

WireGuard Handshake Never Completes

First, verify the endpoint IP and port (51820) are correct. Then ensure your WAN firewall does not block outbound UDP on port 51820. Additionally, check that the private key in the tunnel config and the public key in the peer config both come from the same Proton VPN configuration file — mixing keys from different configs will always cause a failure.


Summary

This guide covered the complete end-to-end setup of Proton VPN WireGuard as a policy-based routing gateway in pfSense 2.7.x, including per-VLAN traffic control, dual IPv4/IPv6 tunneling, leak-proof DHCP-based DNS, and a scalable multi-tunnel architecture. The table below summarizes the key steps:

StepWhat was configured
1WireGuard config file downloaded from Proton VPN (Router platform)
2WireGuard package installed in pfSense Package Manager
3WireGuard tunnel created with IPv4 (10.2.0.2/32) and IPv6 (2a07:b944::2:2/128) addresses
4Peer added with server public key, endpoint IP:51820, AllowedIPs 0.0.0.0/0 and ::/0
5tun_wg3 assigned as a pfSense interface with static IPv4 and IPv6
6IPv4 gateway (10.2.0.1) and IPv6 gateway (2a07:b944::2:1) added with non-local route option
7Manual Outbound NAT enabled; IPv4 and IPv6 NAT rules configured for VLAN subnets
8VLAN firewall rules updated with VPN gateway override for policy-based routing
9DHCP pushes Proton DNS (10.2.0.1, 10.2.0.2, 2a07:b944::2:1, 2a07:b944::2:2) to VLAN clients
10IPv6 dual-stack confirmed working via ULA local addresses + Proton GUA tunnel address
11Multiple tunnels scaled by incrementing IP scheme (10.3.x, 10.4.x, 2a07:b944::3:x...)
12Verification and troubleshooting steps, including disabling gateway monitoring

Note: WireGuard® is a registered trademark of Jason A. Donenfeld.