Setup WireGuard VPN Server on Pfsense

pfsensepfsense

Disclaimer

warning

Since WireGuard is not officially supported by Pfsense yet. So treat this guide as BETA. Once official support is addded, this article will be updated.

Overview

OpenVPN is the standard of choice for VPN technology.

However, a new VPN technology, called WireGuard, is promising to shake things up.

What makes WireGuard better than OpenVPN?

  • Much more secure (latest standards only, as opposed to OpenVPN which uses several standards)
  • Much less bloated code (4,000 lines of code) vs OpenVPN (100,000 lines of code), which makes audits and maintenance much easier.
  • Much faster than other VPN tunnels. Source

  • As you can see from the photo:
    • Throughput was 291% faster on WireGuard than on OpenVPN.
    • Ping was 282% faster on WireGuard than on OpenVPN.

Limitation

note
  • The following guide assumes that your VPN server IP won't change. If your service provider changes your public IP, you'll have to tweak the configuration file (for every client) with every new IP change.
  • Alternatively, you could setup a Dynamic DNS for your VPN server, and even if the ISP changes your public IP, this won't affect your clients connecting to the VPN server. This is outside of the scope of this post.

VPN Definitions

  • Server
    • Any device where the VPN tunnel will be terminating to
    • in my case...Pfsense firewall
  • Client or Peer
    • Any device that's going to be connecting to the Server
    • in my case...iPhone, Macbook, and Windows PC

What you need to make it work

If you have a bare hardware on which you've installed Pfsense (example. on a spare computer):

  • Add another 1 x 1gbps NIC (with no cable plugged in)

If you have a firewall appliance from Netgate (or similar hardware):

  • Must have an unused port

Pfsense Version

I'm using Pfsense 2.4.5-release P1, this is based on FreeBSD 11.3. This means I'll need packages from FreeBSD 11.x.

Install Wireguard packages for FreeBSD (which is Pfsense is based on)

Go to FreeBSD 11.x packages Then search for wireguard and you'll see the latest versions. In my case I saw:

https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/wireguard-go-0.0.20200320.txz
https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/wireguard-1.0.20200513.txz

As you can tell, they were updated on 2020-03-20 and 2020-05-13. But it will most likely be updated, so be sure to use the latest.

Go to Pfsense, diagnostics, select command prompt

  • Under command, type in the following:
pkg add https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/wireguard-go-0.0.20200320.txz
pkg add https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/wireguard-1.0.20200513.txz

Some users might get an error, which tells them that Bash is not installed.

pkg add https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/bash-5.0.17.txz
  • Install Bash with the code above
  • Repeat steps for WireGuard

Install Wireguard script (made by community) for Pfsense

This is unofficial script, made by community members.

  • Go to Pfsense, diagnostics, select command prompt
    • Under command, type in the following:
pkg add https://github.com/Ashus/pfSense-pkg-wireguard/releases/download/v1.0.1b/pfSense-pkg-wireguard-1.0.1-freebsd11-

Assign Interface in Pfsense

Go to Pfsense, Interfaces, Assignments

  • You'll see Interface OPT1 (in my picture you'll see I renamed it already to VPN) and then tunwg0
  • Select Add
  • Select Save

Go to Pfsense, Interfaces, Select VPN

  • Select Enable
  • Description: VPN
  • Leave other settings on defaults
  • Select Save

Enable Port Forwarding on Pfsense

  • Pfsense, Firewall, NAT, under Port Forward tab, select Add
    • Interface: WAN (since this connection will be coming from the WAN)
    • Protocol: UDP (since WireGuard uses UDP only)
    • Destination: WAN address
    • Destination Port: 51820 (I chose as 51820)
      • I recommend using any ports from 49152 to 65535. These are called ephemeral ports, which are dynamically opened by your clients on your Pfsense firewall.
    • Redirect target IP: 192.168.1.1 (I set as my Pfsense LAN IP)
    • Redirect target port: 51820 (to match above)
    • Description: NAT rule to allow Wireguard traffic

Setup Firewall Rule to allow WireGuard traffic

  • By default, pfsense doesnt allow any traffic on interface VPN. Let's allow traffic, so any connected clients will be able to reach the internet.
  • Pfsense, Firewall, Rules, Select VPN tab
    • Action: Pass
    • Interface: VPN
    • Address Family: IPv4
    • Protocol: Any (it means any traffic like UDP, TCP, ICMP=ping, etc.)
    • Source: Select Network and type 10.0.0.0/24
      • this will allow multiple clients connected to the VPN at once
    • Description: Allows traffic on VPN Wireguard subnet

How to setup WireGuard on Mobile (both iPhone/Android)

Mobile Step 1: Let's configure WireGuard Interface on Pfsense

  • Pfsense, VPN, Wireguard, Select Inteface tab
    • Address: 10.0.0.0/24 (this must be on a separate subnet from all of your networks, I chose 10.0.0.0/24)
    • Listen Port: 51820 (I chose as 51820)
      • I recommend using any ports from 49152 to 65535. These are called ephemeral ports, which are dynamically opened by your clients on your Pfsense firewall.
    • DNS: 1.1.1.1 (I chose a public IP of Cloudflare to make it easy) (you could use a local DNS server like Pihole as well. see my notes at the end of this article)
    • Click Generate button, which will auto-fill the private and public key pair. (aka server keypair)
      • You'll need the Public Key later on for Step 4.
      • In my case bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=

Mobile Step 2: Let's configure WireGuard Interface on Mobile Phone

  • On iPhone/Android:

    • Generate new tunnel from scratch

    • Name it: Pfsense-Home (or however else you'll know where you're connecting to)

    • Addresses: 10.0.0.2/24 (since I chose 10.0.0.2 to be the IP of my iPhone)

    • Port: 51820

    • DNS: 1.1.1.1 (I chose a public IP of Cloudflare to make it easy) (you could use a local DNS server like Pihole as well. see my notes at the end of this article)

    • Select Generate Keypair, which will generate a private and public key (aka client keypair)

    • For Public Key, select Copy Public Key and you'll need to paste into Pfsense (somehow)

      • This was aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=

Mobile Step 3: Let's configure WireGuard Peer on Pfsense

  • Pfsense, VPN, Wireguard, Select Peers tab, click Add button
    • Name: My_iPhone (this will make identification of multiple clients much easier)
    • Public Key: Paste Public Key from Step 2.
      • In my case: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=
    • Allowed IPs: 10.0.0.2/24 (I will use 10.0.0.2 as the IP of My iPhone that will be connected on this tunnel)

Mobile Step 4: Let's configure WireGuard Peer on Mobile Phone

  • On iPhone/Android
    • Select Add Peer
    • For Public Key: Paste in the value from Step 1.
      • In my case: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=
    • Endpoint: Your_Home_Public_IP:51820 (your home's public IP and port 51820 we setup previously)
    • Allowed IPs: 0.0.0.0/0 (this allows all web traffic)

Mobile Step 5: Restart WireGuard Service on Pfsense

caution

I've experienced a problem when I added a new client (called peer) to Pfsense Wireguard Server, and when I connected the VPN tunnel from the client. The VPN tunnel connected, but none of the websites were working.

The fix? Go to pfsense, dashboard, click on restart (clock-wise arrow) on Wireguard to restart it.

Optional Step: View current settings in Pfsense

For those who like to use the terminal:

  • SSH into Pfsense
cd /
cd usr/local/etc/wireguard
cat tunwg0.conf

Enable the VPN tunnel on iPhone

  • On my iPhone, I completed WireGuard process and saved the profile.
  • Now that the profile is saved on the iPhone, there are 2 ways of activating WireGuard:
  1. Open WireGuard, enable it
  2. Open Settings, VPN, enable it

Verify connection from Pfsense

  • Pfsense, Status, WireGuard
    • Endpoint: YY.YY.YY.YY is IP owned by my cellphone provider.
    • Latest Handshake: 10 seconds ago (shows how long ago the client connected to this pfsense)
    • Peer: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa= (which was the public key from Step 2)

  • Pfsense, Diagnostics, pfTop
    • search port 51820

We can see 2 things:

  • A single UDP packet that was sent from source YY.YY.YY.YY (cellphone provider) on random port 51091 to destination 192.168.1.1 (my pfsense LAN IP) over port 51820. This is how the VPN tunnel is established.
  • Continuous UDP traffic going from source XX.XX.XX.XX (my public IP at home) on port 51820 to destination YY.YY.YY.YY (cellphone provider) on random port 39040. This means my client (my iPhone over LTE with VPN turned on) has an active connection to the server (pfsense at home).

Verify connection from iPhone

  • Disable Wifi
  • Keep LTE enabled
  • Enable VPN tunnel
  • Go to dnsleaktest.com
  • You'll see the IP of the home, X.X.X.X
    • If you select Standard Test, this will verify your DNS provider (I set it to be 1.1.1.1 earlier)
    • You'll see Cloudflare (which matches Cloudflare's IPs 1.1.1.1)

How to setup WireGuard on Mac OS

MacOS Step 1: Install Mac OS

Wireguard has an official app for Mac OS. Open on MacOS

MacOS Step 2: Setup MacOS Client

  • Open Wireguard, Select Add emptry tunnel
  • You'll see the automatically generated client public and private keys.

  • Copy the public key, ccccccccccccccccccccccccccccccccccccccccccc=
    • which you'll need to paste into pfsense in step 3.
  • Paste in the following after the PrivateKey:
Address = 10.0.0.3/24
DNS = 1.1.1.1
[Peer]
PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=
AllowedIPs = 0.0.0.0/0
Endpoint = Your_Home_Public_IP:51820

[Interface]:

  • PrivateKey = ... (this was auto-generated)
  • Address = 10.0.0.3/24 (I used for my macbook, since I've already used 10.0.0.2/24 for my iPhone)
  • DNS = 1.1.1.1 (I chose a public IP of Cloudflare to make it easy) (you could use a local DNS server like Pihole as well. see my notes at the end of this article)
    • note: if you forget to include this DNS line, websites might not be routable

[Peer]:

  • PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb= (which is my Pfsense server's public key)
  • AllowedIPs = 0.0.0.0/0 (this allows all web traffic)
  • Endpoint = Your_Home_Public_IP:51820 (your home's public IP and port 51820 we setup previously)

MacOS Step 3: Setup Peer in Pfsense

  • pfsense>VPN>WireGuard>Peers>Add
    • Paste into public key the public key from step 2.
      • ccccccccccccccccccccccccccccccccccccccccccc=
    • Name it: My_Macbook (or whatever else helps you identify the device)
    • Allowed IPs: 10.0.0.3/24
    • Save

MacOS Step 4: Restart WireGuard Service on Pfsense

caution

I've experienced a problem when I added a new client (called peer) to Pfsense Wireguard Server, and when I connected the VPN tunnel from the client. The VPN tunnel connected, but none of the websites were working.

The fix? Go to pfsense, dashboard, click on restart (clock-wise arrow) on Wireguard to restart it.

How to setup WireGuard on Windows

Windows Step 1: Install application for Windows

Wireguard has an official app for Windows. Link

Windows Step 2: Setup Windows Client

  • Run, Select Add empty tunnel
  • It will generate the client public/private keypair.
  • Copy the public key ddddddddddddddddddddddddddddddddddddddddddd=
    • and you'll need this for step 3.

Paste in the following into

Address = 10.0.0.4/24
DNS = 1.1.1.1
[Peer]
PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb=
AllowedIPs = 0.0.0.0/0
Endpoint = Your_Home_Public_IP:51820

[Interface]:

  • PrivateKey = ... (this was auto-generated)
  • Address = 10.0.0.4/24 (I used for windows laptop, since I've already used 10.0.0.2/24 for my iPhone and 10.0.0.3/24 for macbook)
  • DNS = 1.1.1.1 (I chose a public IP of Cloudflare to make it easy) (you could use a local DNS server like Pihole as well. see my notes at the end of this article)
    • note: if you forget to include this DNS line, websites might not be routable

[Peer]:

  • PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb= (which is my Pfsense server's public key)
  • AllowedIPs = 0.0.0.0/0 (this allows all web traffic)
  • Endpoint = Your_Home_Public_IP:51820 (your home's public IP and port 51820 we setup previously)

Windows Step 3: Setup Peer in Pfsense

  • pfsense>VPN>WireGuard>Peers>Add
    • Paste into public key the public key from step 2.
      • ddddddddddddddddddddddddddddddddddddddddddd=
    • Name it: Windows_Laptop (or whatever else helps you identify the device)
    • Allowed IPs: 10.0.0.4/24
    • Save

Windows Step 4: Restart WireGuard Service on Pfsense

caution

I've experienced a problem when I added a new client (called peer) to Pfsense Wireguard Server, and when I connected the VPN tunnel from the client. The VPN tunnel connected, but none of the websites were working.

The fix? Go to pfsense, dashboard, click on restart (clock-wise arrow) on Wireguard to restart it.

How to protect your DNS traffic

  • I previously used a public DNS server 1.1.1.1 to prove that the tunnel works.
    • But what if you want to have more control over your DNS traffic? Well, I switched the configuration to my Pihole DNS 192.168.2.2 (which I setup previously to work with Pfsense)
  • On iPhone, connect to LTE, disable wifi, enable VPN, and go to any website
    • Back on the local network, go to Pihole dashboard 192.168.2.2, and you'll see IP 10.0.0.2 (my cellphone which is currently connected via VPN). This worked!
    • On iPhone, go to dnsleaktest.com and do the Standard Test. In the end, you'll see the IPs that you had setup in Pfsense at home. This worked!

You have 2 options when connecting from the client:

  • Set your DNS as 1.1.1.1 (a public DNS server)
    • That means your DNS traffic will be unfiltered
  • Set your DNS as 192.168.2.2 (my pihole IP)
    • That means your traffic will be filtered by pihole.
    • This will make your DNS traffic faster, as ads and 3rd party scripts will no longer be routable (because they will be blocked by Pihole) and therefore your VPN experience will be faster!

Test #1: WireGuard VPN over ISP's Fiber Optic Cable

Tests done with speedtest.net:

  • Home Fiber (over LAN, No VPN)
    • Ping: 3 ms
    • Download: 177 mbps
    • Upload: 177 mbps
  • Work Fiber (over LAN, No VPN)
    • Ping: 2 ms
    • Download: 511 mbps
    • Upload: 510 mbps
  • Using Work Desktop computer (via ethernet), connected to home's WAN using WireGuard
    • Ping 4 ms
    • Download: 92 mbps
    • Upload: 65 mbps

Conclusion:

  • As you can see, the ping went from 3 ms to 4 ms and speed dropped from 177 mbps to 92 mbps.

Test #2: WireGuard VPN over Cellular Provider 1 LTE Connection

note

Take the tests with a grain of salt, as cellular LTE connection varies a lot.

Tests done with speedtest.net:

  • On iPhone, using LTE with provider 1, without VPN
    • Ping: 27 ms
    • Download: 50 mbps
    • Upload: 10 mbps
  • On iPhone, Using LTE with provider 1, with WireGuard enabled, connected to Home (which has a Fiber optic connection, with ping of 3 ms and 177 mbps down/up)
    • Ping: 59 ms
    • Download: 35 mbps
    • Upload: 4 mbps

Conclusion:

  • The importance of this test is NOT the speed or latency, but simply the difference between the non-VPN and VPN test.
    • Latency went up 118% when WireGuard was turned on.

Test #3: WireGuard VPN over Cellular Provider 2 LTE Connection

note

Take the tests with a grain of salt, as cellular LTE connection varies a lot.

Tests done with speedtest.net:

  • On iPhone, using LTE with provider 2, without VPN
    • Ping: 29 ms
    • Download: 30 mbps
    • Upload: 1 mbps
  • On iPhone, Using LTE with provider 2, with WireGuard enabled, connected to Home (which has a Fiber optic connection, with ping of 3 ms and 177 mbps down/up)
    • Ping: 60 ms
    • Download: 25 mbps
    • Upload: 3 mbps

Conclusion:

  • The importance of this test is NOT the speed or latency, but simply the difference between the non-VPN and VPN test.
    • Latency went up 106% when WireGuard was turned on.

Limitation of Wireguard

  • While you can ping IPs on your LAN, you won't be able to ping hostnames. It doesnt matter if you're using a public DNS like 1.1.1.1 or private DNS like my pihole 192.168.2.2.

UPDATE:

  • I've read reports online that suggest the following setup:
    • Client must use /32 subnet (but not /24 subnet).
    • Server must use /24 subnet.
  • I've tested with client/server using /24 (as per my article) and with new proposed setup of client /32 and server /24...and they both worked!

Conclusion

WireGuard VPN is awesome!