Road-Warrior Style WireGuard VPN – iOS to pfSense 2.6 (ipv4/ipv6)

ENV: pfSense 2.6.0-RELEASE (amd64) as a KVM Guest on Proxmox 7.2
iOS 15/16 with the Official WireGuard App

Install

On the latest pfsense install WireGuard through the System > Package Manger Menu. Package is “WireGuard”. pfsense package version used in this guide is 0.1.6_2.

Configure WireGuard Server

Under WireGuard Settings Tab
Make sure Enable WireGuard is checked.
Set Interface Group Membership: None

Add New Tunnel

Under VPN > WireGuard add a new Tunnel.
Desc: “Road Warrior Clients”
Listen Port: can be default for easy of client connections, or custom.
Generate a Key Pair
Save

Setup Interface

Back to the Road Warrior Clients Tunnel
Click on Interface Assignments. This will take you to the interfaces page.
At the bottom select the net WG tunnel next to “Available network ports” and click add.
Enable Interface ticked.
Set an interface Description. I did “WGRoadWarrior”
Set Static IPv4 if using IPv4
Set Static IPv6 is using IPv6
MTU: 1432 is using Only IPv4, 1412 if using IPv6 at all.
MSS: Same as above
Static IPv4 Configuration >
Address: The GW Address of your desired range and mask
No GW
Static IPv6 Configuration >
My particular ISP has delegated me a /48 range. (Aussie Broadband) Out of that I’ve separated a /64 range for VPN clients.
VPN Clients will need to be statically set to a v6 address within whatever range you assign. WireGuard doesn’t support DHCP, random address assignment, or RA over VPN at this time. IPv6 Privacy Extension is defined in RFC 4941 cannot be applied here.
Again no GW.
Save.

Firewall Rules

Firewall > Rules > <Your WG RW Rule List>
Add at least an allow all IPv4+6 rule to get you going.
This will be traffic from clients back to your FW.

Add the first client

VPN > WireGuard > Tunnels > edit <your tunnel>
Add Peer >
Tick Enable Peer
Add a description, usually the username+devicetype
Dynamic Endpoint: Ticked
Keep Alive: blank
Public Key: (See below)
Pre-Share Key: <Press Generate>
Allowed IPs: Add the intended configured Static IPv4 and IPv6 Addresses here each in their own field. /32 and /128 masks.
Before Saving well need to generate the priv/public keypair either on the device or using WireGuard on a different server.
I’ve found it easiest to make the client keypairs to ssh to pfsense and run

wg genkey | tee privatekey | wg pubkey > publickey && cat privatekey && cat publickey

That will cat a new clients private key and public key to terminal.
Put the Public Key in the pfsense client creation page and click Save, then Apply.
Take private key details and add them to a config file on another server that is fit to hold onto client configs.
The template for that file is:

[Interface]
PrivateKey = <client private key here>
ListenPort = <same as server listen port>
Address = <static ipv4 address in cidr format (example "192.168.5.10/24">, <static ipv6 address in cidr format>
DNS = <ipv4 DNS Server IP on your LAN>, <ipv6 DNS Server IP on your LAN>
MTU = <1434 for IPv4 only / 1412 otherwise> 

[Peer]
PublicKey = <Servers Tunnels WG Public Key>
PresharedKey = <PSK for this client>
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = <DDNS/FQDN hostname of your pfsense VPN server>:<configured listen port of server>

With the config file made. Use a console based qrcode generator to present that config file for scanning by the client. Example:

qrencode -t ansiutf8 < client1

On the first clients iOS device. Install and Open WireGuard.
Add a new tunnel, Create from QR Code, Scan Code.

The WireGuard App will create a system VPN profile that can be manually enabled/disabled in the settings app. The WireGuard app does not need to remain open once the profile has been loaded.

Optionally configure it as an on-demand tunnel. This will ensure the connections comes up whenever the device is off trusted wifi, and optionally whenever it is on mobile broadband.

I use this setup as a way of extending IPv6 beyond my home network to wherever I am.
Has worked flawlessly since the day it was setup.

Leave a Reply

Your email address will not be published. Required fields are marked *