Set up WireGuard Point-to-Site VPN on pfSense
Today I want to show how to set up a Point-to-Site VPN (P2S) by using WireGuard on pfSense. In my post below I will also show how to set up a Site-to-Site VPN (S2S) by using WireGuard on pfSense.
Actually WireGuard doesn’t have a classic Point-to-Site VPN or Client and Server concept, all participants (peers) are equally privileged. In this case our pfSense applicance with the WireGuard package is the server with a static endpoint on which all clients will be configured as peers with a dynamic endpoint. On the clients we will configure in contrast just one peer, the pfSense applicance.
Though WireGuard does not have a concept of “Client” and “Server” per se, in this style of deployment the firewall initiates connections to a remote peer but the peer never initiates back to the firewall. In this way, the firewall behaves like a “Client” and may be referred to as such in this document. The remote peer may also be referred to as “server”.
Technically every WireGuard tunnel is a peer to peer connection, but there are three main ways a WireGuard tunnel can be configured depending on whether or not a peer endpoint is known or defined:
- Site-to-Site (peer endpoint filled in on both sides)
- Remote Access “Server” (endpoint only filled in on remote peers)
- Remote Access “Client” (endpoint only filled in locally, not on the “server” peer)
Any of those roles can technically be configured no matter how the peer endpoint settings are defined, but not defining an endpoint on one side or the other limits the capacity in which a peer can operate.
Typically, a tunnel is defined with a known peer IP address or hostname for the endpoint, which could take advantage of Dynamic DNS for dynamic peers. This is the most secure method as it locks the tunnel down to specific known peers, but that is not always practical.
In the case of remote access style setups, the peer endpoint address is typically unknown and can change at any time. In this case, the peer endpoint can be left blank and WireGuard will accept connections from any remote address, validating the key instead.
Please note that the WireGuard pfSense add-on package is still under EXPERIMENTAL state as of today!
WireGuard is a communication protocol and free and open-source software that implements encrypted virtual private networks (VPNs), and was designed with the goals of ease of use, high speed performance, and low attack surface. It aims for better performance and more power than IPsec and OpenVPN, two common tunneling protocols. The WireGuard protocol passes traffic over UDP.
In March 2020, the Linux version of the software reached a stable production release and was incorporated into the Linux 5.6 kernel, and backported to earlier Linux kernels in some Linux distributions. The Linux kernel components are licensed under the GNU General Public License (GPL) version 2; other implementations are under GPLv2 or other free/open-source licenses.
Installation on pfSense
I will use a virtual machine on Hyper-V where pfSense 2.6.0 is installed on.
WireGuard is available as an experimental add-on package on pfSense Plus 21.05, pfSense CE 2.5.2, and later versions. The settings for the WireGuard add-on package are not compatible with the older base system configuration.
The WireGuard package is still under active development. Follow the development progress on the developer’s YouTube channel
To install the WireGurad add-on package on pfSense we open as usual the Package Manger under System –> Package Manger
Here we search under Available Packages for WireGuard. As of today version 0.1.6_2 is the latest which I will install and therefore click on the install button.
The package is still EXPERIMENTAL!
WireGuard(R) is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPSec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry. This package is EXPERIMENTAL.
At this time this code is new, unvetted, possibly buggy, and should be
considered “experimental”. It might contain security issues. We gladly
welcome your testing and bug reports, but do keep in mind that this code
is new, so some caution should be exercised at the moment for using it
in mission critical environments.
Configure WireGuard on pfSense
From now on we have under the VPN menu a new item with WireGuard where we can set up and configure WireGuard.
Configure the Tunnel
First we need to add a tunnel by clicking on Add Tunnel.
Here we have to enter a description for the tunnel, the listening port we can be left empty in order to use the default UDP port 51820.
For the private and public interface keys we can generate a new key pair by clicking on the Generate button.
Further we need to enter here an interface IP address which will be used for the transit network where the traffic between the external VPN clients and pfSense (WireGuard) will traverse, similiar as for an IPSec S2S route based VPN. We need to enter here an IP address which isn’t in use so far or overlap with our other subnets on the network.
Consider to use here a subnet mask which will cover the amount of all external clients you want to connect to. Each external client need one IP from this subnet.
Because I will use here a /24 subnet I can connect up to 253 external clients, 1 IP is reserved for pfSense itself.
For a site-to-site VPN tunnel you just need two IP addresses for the tunnel and therefore a /30 subnet will be fine.
That’s all for the tunnel configuaration and we now need to add a peer configuration which will represent the external clients who wants to connect to our network.
Configure the Peers (external clients in our case)
After saving the tunnel configuration above, we get the red warning message that the WireGuard service so far is not running. To get rid of it you just need to enable WireGuard in the settings menu as shown in the next screenshot below.
As mentioned to start the WireGuard service you just need to check Enable Wireguard in the settings.
Now go back to the Peers menu and click on Add Peer. As mentioned this peer will be one of the external clients who wants to connect to our network.
One downside of WireGuard compared with OpenVPN is that you need to configure for each external client a dedicated peer configuration. Also you need to configure on the client a fix internal IP instead of using DHCP.
The new peer is by default enabled. So first we need to assign our previously created tunnel to this peer. Further we need to enter a description for the peer. I will also use by default the dynamic endpoint.
The Endpoint is the public IP address and port number where WireGuard is listening and sending traffic through the VPN tunnel. As this peer will be one of our external clients, they usually don’t have a static public IP address and it will change frequently instead.
Therefore we will later configure on the clients a static endpoint for the server (pfSense WireGuard) with its static public IP and port number it is listening.
Between two WireGuard peers, just one peer needs to be configured with a static endpoint. The peer with the static endpoint will wait until the peer with the dynamic endpoint (our external clients), will inititate a connection to it and then dynamically update its endpoint.
The public key we can generate on the client. Further down I will show in detail how to configure the Windows VPN client for WireGuard. In order to generate the public key with the corresponding private key (private/public key pair), you can already download the Windows VPN client under the following link.
WireGuard VPN Clients
After installation the client will be opened and we can click on Add Tunnel –> Add empty tunnel … to generate the private/public key pair.
As you can see the new empty configuration already includes a new private/public key pair, which we can use to create the Peer on pfSense (WireGuard).
Copy the public key and paste it into our peer configuration on pfSense.
The Pre-shared Key for the peer is optional but we just need to click the Generate button and it will enhance security.
An optional pre-shared key which provides an additional layer of symmetric-key cryptography on top of the public key cryptography for post-quantum resistance.
Under the last section for the peer configuration named Address configuration we need to add all subnets or hosts we want to access from the external client.
You need to enter here all subnets from your network you want to access from external (the VPN clients).
We also need to enter here the subnet or IP address from the external VPN client itself which is within the transit network range.
Finally click on Save Peer and apply the changes to pfSense.
Next step is to configure the firewall settings to allow the VPN traffic.
Configure Firewall Settings
Unfortunately WireGuard doesn’t create an automatic rule like OpenVPN does to allow VPN connections to the listening UDP server port we configured for WireGuard.
So we need to add the firewall rules on Firewall > Rules, WAN tab to allow UDP traffic to the port for this WireGuard tunnel (WireGuard and Rules / NAT)
Add firewall rules on the common Firewall > Rules, WireGuard tab to pass traffic inside the VPN (WireGuard and Rules / NAT)
For testing purpose I will allow all traffic, in production use you will normally filter which traffic is allowed.
Set up the Windows Client
You can download the clients at the following link https://www.wireguard.com/install
After the installation the Windows WireGuard client will get opened like below. As already mentioned above for creating a private/public key pair, we will click here Add Tunnel –> Add empty tunnel … to create a new configuration.
Use here the same private/public key pair as you created before to enter the public key for the peer configuration on pfSense.
Under the following link you will see a sample configuration from Netgate.
I will also use it and adjust or add the parameters to fit with my configuration. Under the Interface configuration section (client peer site), the Address is an IP address from my transit network on pfSense and the WireGuard tunnel is here configured with the IP 172.19.10.1/24.
Here I have to use an address from that subnet which is not already in use, so I will use for the first client the next IP with 172.19.10.2/24.
Further I will enter two DNS servers from my network in order the VPN clients can resolve DNS names within the network.
Under the peer configuration section (pfSense WireGuard peer) I was adding the public key from the tunnel configuration and because I was generating a pre-shared key for the peer (client), I also need to enter this key here.
Also I need to enter all allowed IPs which are the IPs in the peer configuration section, you need to enter here all subnets and hosts you want to access from your external client.
If they not listed here, your Windows client will not have a routing entry for these subnets. So on the client the configured allowedIPs, will also tells the client to route all of them through the tunnel.
And also as mentioned at the beginning, as the client is configured as dynamic endpoint, for the server peer we need to enter the static endpoint (public IP and port) from pfSense (WireGuard).
After the client is establishing a connection, it will update its route table with the allowedIPs range to route through its tunnel IP address.
To establish a connection to our network we now just need to click on Activate.
You can see all external connected clients within the Status section from WireGuard as shown below.
In order that your external VPN clients can access all the internal systems in your network, you configured as allowed IPs here, the internal systems of course need to know the route to your transit network where the external clients and the WireGuard tunnel had assigned an IP address from.
WireGuard VPN Client Configuration Example