I published this guide several years ago to expose my thinking and configuration to the scrutiny of networking experts and benefit less experienced users with an easy to follow but comprehensive guide. I would like to thank all those who contacted me with questions or provided feedback that contributed to making this guide what it is today. I continue to appreciate feedback on any errors, configuration or areas you think would benefit from additional clarification so please don’t hesitate to contact me by email.
Several iterations ago I revised my guide towards becoming a foundational piece in a series of guides aimed at helping users create a SOHO system capable of self-hosting numerous services and supporting migration away from cloud providers to take ownership of their own data.
Although this baseline configuration remains largely the same as the previous version, there are a few areas that have been improved due to increased or refined knowledge, or as a result of the pfSense 2.5.0 release including:
To learn more about the numberous changes included with pfSense 2.5.0, please review Netgate’s new features and changes list. OpenVPN 2.5 is incorporated into this release and its changelog is here for reference.
I created this guide towards supporting typical residential and/or small office ISP bandwidth capabilities. I’ve seen good results on both cable and fibre providers with up/download capabilities in the 5/20 to asymmetric gigabit range. I’ve also heard of positive experiences on 4G LTE connections so long as the underlying connection is stable.
Although this guide focuses on building out the core local area networks (VPN, clearnet, guest and management), I’ve provided some additional details here as to the rest of my VLANs setup for some context on how I segregated my other traffic.
Unencrypted ‘clearnet’
Used for general purpose web access when an encrypted line isn’t a requirement.
General secure VPN
Primary LAN network where all traffic which exits is encrypted via OpenVPN and exits to the internet via one of several AirVPN end points.
Self-hosted subnet
I have a number of self-hosted services that reside in a VLAN and have policy routing in place to steer outbound traffic through the clearnet, AirVPN or other privately hosted OpenVPN gateways. The particular gateway is selected depending on the specific services needs and risk profile.
Guest network
Effectively this exposes my native unencrypted unsecured ISP line complete with OpenDNS name resolution. Used primarily by visitors who require internet access but also acts as a backup in case AirVPN goes down for any reason. Firewall prevents access to all local resources including user devices, file servers and core infrastructure.
Management network
Used for native hardware access to devices such as wifi access points as well as interfaces intended to be utilised only by an admin user, for example, IPMI management consoles, NUT, SNMP monitoring interfaces and headless servers.
Security cameras
Subnet which various security cameras are connected to. This subnet is heavily firewalled to prevent anyone from attempting to gain access to my home network via compromising an external cable or camera. A Windows Server 2019 VM runs my NVR software and resides in the same VLAN and subnet as the cameras themselves ensuring that the camera traffic is primarily handled by my switch rather than adding avoidable load to pfSense.
Internet of Things (IoT)
A subnet that untrusted home automation devices such as smart plugs and various sensors connect to with severely limited access to primary subnets.
Multiple DMZ’s
I run several DMZ subnets to provide isolated, de-restricted zones for numerous clients and servers which need to be accessed remotely, for example FiOS TV, Kodi video player, Plex/Emby, Game consoles, VoIP devices and several game servers.
Please be aware this recommendation is unbiased. I have not, and do not intend to, profit from recommending AirVPN or any other VPN provider now or in the future. The link below does not include any referral codes.
I’m still using AirVPN as my primary VPN provider, downtime is rare and performance on the whole is still amongst the best I’ve encountered to date. There are a number of VPN providers on the market but the reasons why I originally went with AirVPN are still valid several years later, i.e
If you haven’t got an AirVPN subscription, you can create an account here.
The following diagram illustrates the basic network topology of my network.
I had my Verizon ONT converted from the original coaxial cable to a Cat5 cable by Verizon which allowed me to connect my pfSense box directly to Verizon’s network without needing to utilise their modem for anything other than enabling some TV set top box functionality. The cost of the conversion was free if done as part of an upgrade to a 150mbps service or faster.
A VLAN capable switch is required to provide support for virtual subnets and also provides additional ports for multiple Wi-Fi access points enabling whole home coverage. I’ve listed a few cost-effective switch options in the hardware section below.
Although it is possible to build a pfSense router from pretty much any old hardware, the following are worth bearing in mind as you select hardware.
CPU
Something relatively modern to reduce power consumption.
Prefer higher clock speeds over higher core counts.
AES-NI hardware acceleration will help with OpenVPN encryption.
RAM
Preferably ECC.
Avoid over spending on fancy LEDs and super aggressive CAS timings.
8/16GB is more than adequate, even with memory intensive packages like Snort or pfBlocker.
Networking
Intel network interfaces are the preferred solution. Chelsio cards have good driver support in BSD too.
Avoiding Realtek interfaces due to numerous reliability and performance issues.
Avoid anything that connects via USB.
Storage
Prefer enterprise class SSDs for write endurance and power loss protection.
SATA 6gbps is fine, PCIe4 NVMe isn’t necessary.
Configure as a matched pair in a ZFS mirror configuration for performance and resilience to single drive failure.
SMART capabilities are beneficial to monitor for degradation.
Chassis
I rack mount my server so front facing IO is valuable
Hot swappable 2.5” drive bays beneficial for how-swap drive failures.
Mesozoic period to 2014
2014 to 2015
2015 to 2016
2016 to 2019
2019 to current
A managed switch is required to provide support for the VLANs. The following are suitable options and many are available on Ebay cheaply. Look for 802.1Q support which is the ability to apply VLAN tags to traffic.
MikroTik RB260GS available for around $40. Accompanying VLAN Config guide here
NETGEAR ProSAFE GS108E available for around $50. Accompanying VLAN Config guide here
Cisco sg300-10 available for around $130 (or slightly more with PoE capabilities). Accompanying VLAN Config guide here
If you expect to have multiple heavily used subnets you may wish to consider looking for a switch that offers a 10gigabit uplink port as this facilitates a larger trunk connection to the pfSense router and thereby corresponding higher throughput. I’ve used Cisco SG500, Juniper EX4300 and Brocade 7450 & 7650 to date with good results.
You don’t need to use multiple Wi-Fi access points, each one provides all the VLANs needed. However depending on the size of the property you are trying to provide Wi-Fi access to, additional APs may be beneficial. I’ve provided an accompanying Unifi configuration guide here
Download 2.5.0 release build from here.
I used the 64bit AMD64 USB memstick installer with VGA console that I installed to a 2GB USB stick with Win32 disk Imager.
To reduce complexity and avoid any potential compatibility issues I recommend disabling unneeded features such as on-board RAID controllers and HBA controllers within the BIOS. I disable hyperthreading as it can introduce some slight but avoidable additional latency.
Insert the USB stick in an available USB port and boot the system from the USB stick. You may need the boot options (F11) or use the Boot menu in the BIOS to set device priority appropriately. This menu will time out after a few seconds and select option 1 on your behalf.
Assuming you are in agreement with the copyright and distribution notice, select Accept.
You will be presented with a series of options that gives you the chance to boot to the Rescue Shell or launch the installer. As this is a fresh install, select Install.
Select the required keymap, I used the default keymap. Verified first with the Test default keymap
option.
A change introduced with pfSense 2.4 is the option to use ZFS partitions. Using a mirrored pair of SSD’s for this install provides data redundancy in case of a single drive failure. This should not be considered a backup and is not a replacement for a proper backup strategy for your pfSense configuration.
Select the Auto (ZFS) option.
…change the ZFS Pool type to Mirrored.
Select the pair of disk drives you wish to use for this install, I’ve selected ada0 and ada1 here as indicated by the *
next to them.
Verify your settings are correct, and if so, select proceed.
Note: If you decide to encrypt your volume, please make sure to remember the password as it is unrecoverable. Also worth noting is that the system will not boot until you enter this password at power on so think about the implications of that too before enabling.
It’s possible to configure regular scrubs of these disks to ensure reliable long-term operation and email notifications should the ZFS array develop any health issues during use.
Final confirmation prior to clearing the contents of the disks you selected. Select YES.
Installation will take a short while. Once installation has finished you will be prompted to make any final manual adjustments, select ‘no’.
And then select Reboot.
Your pfSense machine should now proceed to boot from the fresh install. After a short while you should see an option page which looks something like this.
By default the installer configures the first hardware NIC as the WAN port obtaining an address via DHCP from your modem. The second NIC will be configured as your local LAN interface at 192.168.1.1. I usually leave my WAN connection modem disconnected until I’ve finished configuration. There’s a DHCP server running on the LAN interface so if you connect your PC to this port, you should be able to obtain an IP address which will allow you to access the pfSense web configurator to continue the configuration process.
Open a browser and enter http://192.168.1.1
into the address bar. You should be presented with a login screen as shown below. If this doesn’t work, validate the IP address space your PC is using is in the same subnet as pfSense’s local interface.
To login, enter the default username ‘admin’ and the password ‘pfsense’.
After you log in you will notice at the top of the screen a warning advising that the admin password is currently set to the default value. It’s fine to ignore this for now as you will be prompted to change it during the initial configuration.
The configuration wizard will guide you through the initial configuration steps.
Select next to begin.
You’ll be offered the chance to purchase a pfSense gold subscription that offers support benefits.
Select ‘next’ to continue.
Configure this screen as specified below. We’ll use the OpenDNS servers for initial DNS resolution.
The default Time server hostname is usually correctly specified but make sure to set the Timezone to your own specific location.
Configure this page as follows. Most of these options will remain as default, i.e empty.
Select next to continue.
You can give your LAN interface a specific address here if needed. Leave it as 192.168.1.1 for now.
Select Next to continue.
Select a strong password to protect unauthorised access to the web interface.
Select Next to continue.
Click Reload to reload the web configurator.
Consider taking the anonymous survey to help the good folks at Netgate.
Click ‘Finish’ to enter pfSense webConfigurator where you will be presented with the main dashboard and where you will configure the rest of the system from.
We will set up some general configuration options first, using the menu bar at the top of the page.
Navigate to System > General Setup
Enabling the forwarder to be used as a server for the firewall enables pfSense to perform reverse lookups to resolve IP addresses into device names in the firewall logs.
Click Save
Navigate to System > Advanced > Admin Access
In a previous version of this guide I reallocated the web configurator to port 445, but there’s little benefit to security via this trivial obscurity. I now prefer to leave the configurator access as default on HTTPS/443 and secure it with a strong password. There are some other options to configure here though.
We can disable the systems default anti-lockout rule as we will be creating our own during the firewall setup later on.
Enable SSH access to pfSense which we will make use of later.
The webConfigurator will reload and the banner will display a red warning sign indicating pfSense has created SSH keys. Click on ‘Mark all as read’ to remove the warning.
Navigate to System > Advanced > Firewall/NAT
Navigate to System > Advanced > Networking
Allow IPv6:
Hardware Checksum Offloading (Disable):
Higher-level checksums are traditionally calculated by the protocol implementation and the completed packet is then handed over to the hardware. Recent network hardware can perform the IP checksum calculation, also known as checksum offloading. The Ethernet hardware calculates the Ethernet CRC32 checksum and the receive engine validates this checksum. If the received checksum is wrong pfSense normally won’t see the packet, as the Ethernet hardware internally disguards the packet. IP checksum offloading can provide a modest performance improvement.
Disable Hardware TCP Segmentation Offload:
Works by queuing large buffers and letting the network interface card (NIC) split them into separate packets just before transmit. TSO should not be used on machines acting as routers.
Disable Hardware Large Receive Offload (Disable):
LRO works by aggregating multiple incoming packets from a single stream into a larger buffer before they are passed higher up the networking stack, thus reducing the number of packets to be processed. LRO should not be used on machines acting as routers as it breaks the end-to-end principle and can significantly impact performance.
hn ALTQ support:
Leave as default. The ‘hn’ driver is related to Hyper-V.
Suppress ARP handling:
Reset All States:
Navigate to System > Advanced > Miscellaneous
Assuming you are using a EAS-NI enabled Intel processor select the following options. You will need to adjust according to your hardware capabilities if you are not using such a processor.
These are important settings to reduce the chance of leaks in the event the VPN goes down for any reason.
Click Save
We need to identify a parent interface before we can start configuring and assigning VLANs. The parent interface refers to the physical interface that will transfer the VLAN tagged traffic.
Historically the best practice was to leave the parent interface unassigned due to undefined, unpredictable or inconsistent behaviour by some hardware, depending on the manufacturer. There was a chance that tagged traffic could be stripped of its tags and end up allocated to the parent interface introducing a security risk.
Navigate to Interfaces > Assignments and select VLANs
Click ‘+’
Parent Interface: Your preferred parent interface, in my case, em2
VLAN Tag: 10
VLAN Priority: 0
Description: VL10_MGMT
Save
Click ‘+”
Parent Interface: Your preferred parent interface
VLAN Tag: 20
VLAN Priority: 0
Description: VL20_VPN
Save
Click ‘+”
Parent Interface: Your preferred parent interface
VLAN Tag: 30
VLAN Priority: 0
Description: VL30_CLRNET
Save
Click ‘+”
Parent Interface: Your preferred parent interface
VLAN Tag: 40
VLAN Priority: 0
Description: VL40_GUEST
Save
Once complete your VLAN Interfaces should look like this
Create an interface per VLAN.
Navigate to Interfaces > Assignments
Select ‘VLAN10 on em2’ from the available network ports
Click ‘Add’
Select ‘VLAN20 on em2’ from the available network ports
Click ‘Add’
Select ‘VLAN30 on em2’ from the available network ports
Click ‘Add’
Select ‘VLAN40 on em2’ from the available network ports
Click ‘Add’
Your interface page should now look something like this, notice the parent interface (in my example, em2) remains unassigned.
I match the third octet of my IP address to the VLAN ID as this makes remembering which is which easier, so VLAN id 10 = 192.168.10.0
Navigate to Interfaces > Assignments
Click on the label next to ‘VLAN10_MGMT’, its likely to be ‘OPT1’
Configure this interface as follows:-
General Configuration
Static IPv4 configuration
Private Networks
Verify your settings against the image below and Click Save & Apply changes.
Navigate back to Interfaces > Assign and configure the VL20_VPN
interface by clicking on the label next to the VL20_VPN network port. We’ll configure this similarly to the VL10_MGMT Interface except we’ll give it a unique name and IP address.
General Configuration
Static IPv4 configuration
Click Save & Apply changes.
Navigate back to Interfaces > Assign and configure the VL30_CLRNET
interface by clicking on the label next to the VL30_CLRNET network port. We’ll configure this similarly to the VL10_MGMT Interface except we’ll give it a unique name and IP address.
General Configuration
Static IPv4 configuration
Click Save & Apply changes.
Navigate back to Interfaces > Assign and configure the VL40_GUEST
interface by clicking on the label next to the VL40_GUEST network port. We’ll configure this similarly to the VL10_MGMT Interface except we’ll give it a unique name and IP address.
General Configuration
Static IPv4 configuration
Click Save & Apply changes.
I like to set each interface to use x.x.x.100-199 for dynamic addresses and reserve x.x.x.10-99 for static allocations. Depending on the number of devices in your network you may need to adjust this to suit your needs.
Navigate to Services > DHCP Server
Select VL10_MGMT tab and set the DHCP server as follows:-
Verify your settings against the image below (I only display the general options below as the rest are default) and then click Save & Apply
Now we’ll set up the rest of the interfaces. Select VL20_VPN tab and set the DHCP server as follows:
Select VL30_CLRNET tab and set the DHCP server as below.
Select VL40_GUEST tab and set the DHCP server as below. For my guest network you can use your ISP DNS servers or those from a public provider such as Cloudflare which I’ve use here.
Now we’ll generate our required AirVPN certificates. Open a browser and go to airvpn.org, sign into your account and then navigate to Client Area > Config Generator.
Its worth spending some time reviewing the statistics of the potential servers you are considering connecting to before finalising your selection. Click on the server name to see statistics on numbers of users, traffic and latency as well as any historic connectivity issues. I specify individual servers in my connections by IP address as this reduces any chance of DNS poisoning. The IP addresses are generally stable and seldom change in my experience.
Download the certificates to your local machine. Either download one of the packed archives and extract, or download the separate files. You will use these 4 certificates and the .ovpn config file to configure the OpenVPN client in pfSense in the next step.
Back in pfSense’s GUI, create and configure the Certificate Authority.
Navigate to System > Cert Manager > CAs
This is what the certificate authority should look like once you’ve added it
Navigate to System > Cert Manager and select certificates
This is what the certificate authority page should look like once you’ve added it
At the time of the latest revision of this guide AirVPN has updated their infrastructure to OpenVPN 2.5 and supports both AES-GCM and CHACHA20-POLY1305 TLS ciphers.
TLS mode is the most powerful crypto mode of OpenVPN, both for security and for flexibility. TLS mode works by establishing control and data channels that are multiplexed over a single TCP/UDP port. The OpenVPN client initiates a TLS session over the control channel and uses it to exchange cipher and HMAC keys to protect the data channel. TLS mode uses a robust reliability layer over the UDP connection for all control channel communication, while the data channel, over which encrypted tunnel data passes, is forwarded without any mediation. The result is the best of both worlds: a fast data channel that forwards over UDP with only the overhead of encrypt, decrypt, and HMAC functions, and a control channel that provides all of the security features of TLS, including certificate-based authentication and Diffie Hellman forward secrecy.
From the AirVPN server status pages we can learn what version of OpenVPN server is running and what ciphers are supported, for example, in the case of Hercules the following are supported
TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256 TLS-DHE-RSA-WITH-AES-256-GCM-SHA384 TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 TLS-DHE-RSA-WITH-AES-256-CBC-SHA
CHACHA20-POLY1305 AES-256-GCM AES-256-CBC AES-192-GCM AES-192-CBC AES-128-GCM AES-128-CBC
Control channel cipher is specified as TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
, where
protocol: TLS
key exchange algorithm: DHE
. How keys will be exchanged by the client and the server.
authentication: RSA
. Digital signature that shows the type of certificate and verifies the SSL is legitimate.
session cipher: AES
Session cipher
session encryption key size (bits): 256
Session encrpytion bitsize
session encrpytion type: GCM
Session encrpytion type
hash function: SHA
Hashing algorithm that both authenticates messages and ensures data integrity
digest size (bits): 384
Hashing algorithm bitsize
It is important to understand this information as the order of preference for cipher selection is defined by the server, not the client. This guide configures the client to negotiate AES-256-GCM
and fall back to AES-256-CBC
if not possible. If you wish to use a less secure but more performant cipher such as AES-GCM-128
, you will need to specify that in both the Allowed Data Encrpytion Algorithm AND the Fallback Data Encryption Algorithm options due to the position of AES-256-CBC
in the server side cipher ordering.
Navigate to VPN > OpenVPN and select Clients
General Information
remote 199.249.223.132 443
The first four numbers are the IP address, and the last number is the port number.User Authentication Settings
Cryptographic settings
Tunnel Settings
Ping Setting
Advanced Configuration
client; persist-key; persist-tun; remote-cert-tls server; prng sha256 64; mlock; auth-nocache;
I’ve provided a brief summary of each of these parameters below. A more complete description can be found in the OpenVPN manual.
client: Specifies this is a client configuration.
persist-key: Don’t re-read key files across OpenVPN client restarts.
persist-tun: Don’t close and reopen TUN/TAP device across OpenVPN client restarts.
remote-cert-tls server: Security option for clients to ensure that the host they connect to is a designated server.
prng sha256 64: Security option to increase Pseudo-Random Number Generator nonce secret length.
mlock: Security option to disables paging to ensures that key material and tunnel data are never written to disk due to virtual memory paging operations.
auth-nocache: Security option to prevent caching username/passwords in virtual memory.
We’ll now assign the OpenVPN interface we just created to a pfSense interface. This will enable us to configure the interface by
Navigate to Interfaces > Assignments
Set up the interface as follows:
Navigate to System > Routing.
It’s not possible to rename the auto-generated default gateway ‘VPN_WAN_VPNV4’ to a more succinct ‘VPN_WAN’. We can achieve the same result by creating a new gateway called VPN_WAN that will replace the default ‘VPN_WAN_VPNV4’ gateway.
We will also provide gateway monitoring via an external address, in this case Route53’s 4.2.2.1
Click on ‘+Add’.
Set the default IPv4 gateway to WAN_DHCP.
After applying the new gateway configuration, the Gateway summary should look like this
Performance
If you see that the CPU core which OpenVPN is running on (use Diagnostics > System Activity) is running at close to 100%, consider using a lighter cipher such as AES-128-GCM. To use AES-128-GCM remove the higher bit count algorithms from the Allowed Data Encryption Algorithm section.
If you are using a CPU without AES consider adding CHACHA20-POLY1305 to the Allowed Data Encryption Algorithm section and see if that helps.
Security
Compression and encryption are a tricky combination. If an attacker knows or is able to control (parts of) the plain text of packets that contain secrets, the attacker might be able to extract the secret if compression is enabled. See the CRIME and BREACH attacks on TLS which also leverage compression to break encryption. This guide is created to prioritise security over performance so compression is not enabled.
These should have been configured during the initial configuration section but as these are important settings to help prevent leaks they are worth verifying.
Navigate to System > Advanced and select Miscellaneous. Scroll down to Gateway Monitoring and ensure the following options are set.
My entire network is synced to my pfSense router with the exception of devices on the guest network which are permitted to sync with external time servers too. The configuration below uses a public pool for time reference but it’s possible to reduce this external dependency by setting up a local GPS based time server. There’s a SBC local time server guide here for reference.
Navigate to Services > NTP
This is how your NTP server should look.
One area I’ve received several questions on is using DNS via SSL/TLS. I’m still personally in favour of using root name resolvers via the DNS Resolver without encryption rather than forwarding SSL/TLS secured queries to public servers. My reasoning is that I would rather have unencrypted names resolved by the authoritative root name servers rather than encrypt my DNS lookups with SSL/TLS but have them resolved by a non authoritative service such as Cloudflare or OpenDNS. This assessment is influenced knowing that unencrypted queries are exposed only through my AirVPN endpoints therefore affording me anonymity. This is an area I’m still evaluating and would welcome feedback.
I make use of three sets of DNS resolvers to provide name resolution across my various local subnets.
In general my system is designed to
To support this feature set, all local devices are set to use the pfSense router as their sole DNS server using the local Resolver or Forwarder. Cached or local names found in the DNS Resolver will be returned to the client and unknown lookups will be resolved externally with either OpenDNS or the root nodes via the AirVPN tunnel. Results returned will be cached for future reference increasing time to response, and also reducing the load on non-local infrastructure.
To reduce any leaks, I lock down the Resolver to the VPN_WAN interface. If the VPN connection goes down, DNS lookups won’t be possible and this is why I provide the guest and clrnet networks as a backup on the rare occasions AirVPN goes down. It is possible to setup multiple simultaneous connections to AirVPN which provides further redundancy and is covered in this guide.
I think this is a good compromise between providing the required functionality and security. I’ve spent time verifying there are no leaks with this setup but there are no guarantees given so please do your own testing.
VL40_GUEST is not added to the interfaces selection as devices on that subnet do not utilise the DNS Resolver or Forwarder to resolve names but reference DNS servers as awarded from the VL40_GUEST DHCP server.
First configure the DNS Resolver, navigate to Services > DNS Resolver > General Settings
local-data: "local.lan. 10800 IN SOA pfsense.local.lan. root.local.lan. 1 3600 1200 604800 10800"
The custom option declares the DNS Resolver as authoritative for the .local.lan
domain. The parameters relate to the following options
Navigate to Services > DNS Resolver > Advanced Settings
Click Save & Apply changes
The DNS Forwarder is used to resolve lookups from the VL30_CLRNET subnet by forwarding queries to the DNS servers specified earlier during the wizard setup. They can be be edited if necessary by navigating to System > General > Setup. The DNS Resolver we previously configured is set to use port 53 so we need to set the forwarder up to use another port. I’ve updated my guide to run this service to port 5335 to avoid any conflicts with the MDNS multicast system as this could cause some conflicts for users looking to use the Avahi package. We set the Forwarder to listen to the localhost (127.0.0.1) network and will later create a port forward to redirect traffic from clients on this subnet.
Navigate to Services > DNS Forwarder
Under domain overrides, click ‘+add’ to create forwarder for local lookups
Click Save & Apply
The complete DNS Forwarder should look like this
It’s worth verifying that basic DNS lookups work before we complicate matters by introducing the VPN DNS server.
Navigate to Diagnostics > DNS Lookup
You should see an IP address returned as well as the time taken to receive the response from the servers configured in the System > General setup page. Successive attempts to resolve the same address should be cached and be returned faster than the original query.
NAT is needed to convert your private local IP addresses to the global registered address space. We’ll set this up for both our WAN and VPN_WAN gateways now. Specifically, we will enable functionality to allow
Navigate to Firewall > NAT and select Outbound
A number of rules will be created automatically. Delete any with ‘500’ in the Destination Port column as we won’t need these.
Click the pencil icon next to 127.0.0.0 / 8 line to edit it.
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
Click the pencil icon next to auto created LAN rule line to edit it
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
Click the pencil icon next to Auto created VL10_MGMT rule line to edit it
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
Click the pencil icon next to Auto created VL20_VPN rule line to edit it
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
Click the pencil icon next to Auto created VL30_CLRNET rule line to edit it
Advanced Outbound NAT Entry
Translation
Port =
Click Save & Apply
Click the pencil icon next to Auto created VL40_GUEST rule line to edit it
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
Click ‘Add bottom’
Advanced Outbound NAT Entry
Translation
Miscellaneous
Click Save & Apply
When you are complete your NAT translation table should look like the image below
We are going to create a few aliases which we will use in the creation of the firewall rules later. These simplify the job of making changes in future especially as we add more interfaces and functionality to our network.
We will create an alias to define the internal subnet we are using.
Navigate to Firewall > Aliases > IP
Click ‘+ Add’
Click Save
I define a list of addresses to route out of the default WAN gateway to avoid unnecessary complications with banks and other services that object to traffic originating from known VPN end points. This alias creates an empty placeholder list for now. It is possible to use pfBlockerNG to enhance this functionality. (Edit: I recommend completing this guide, once everything is verified as working visit the pfBlockerNG guide).
Navigate to Firewall > Aliases > IP
Click Save
We will create a list to define which ports administration traffic flows on, we will allow these ports with a dedicated rule on key interfaces later to ensure we don’t lock ourselves out when configuring the firewall.
Navigate to Firewall > Aliases > Ports
Click Save
We will create a list of ports to define what traffic is permitted to traverse between local subnets. You will need to amend this alias as per your own networks requirements, but this should get you started. To better understand what needs you have, enable firewall logging and review the firewall logs which will illustrate which ports are being used or blocked.
Navigate to Firewall > Aliases > Ports
Click Save
We will create a list of ports to define what is allowed to access the internet. You will need to amend this as per your own networks requirements. Again, if any programs or services you use stop working, check the firewall logs to see if there are any blocked ports being reported.
Navigate to Firewall > Aliases > Ports
Click Save
Firewall are critical component of securing your network and its worth double checking you have this section set up correctly. Errors here could expose your network to unwanted intruders. I split my IPv4 and IPv6 default blocks out currently, but you could combine them into a single rule if you prefer. The order of the rules is important as they are processed from top to bottom. I’ve added images for each interface so you can verify your rules have been created and ordered correctly.
First, set up the WAN interface. With no rules, all inbound traffic is blocked by default but isn’t logged. Add a catch all rule that prevents and more importantly logs inbound traffic so we can be aware of who may be trying to gain access.
If there are two default rules already created on this page its likely you didn’t disable the autogeneration of rules options when you configured the WAN Interface. Click on the cog next to one of the two default rules and ensure the Block RFC1918 networks and Block BOGON network options are cleared. We will replace these with our specific rules to enable more fine-grained control.
Navigate to Firewall > Rules > WAN
Click [Save]
Your WAN interface should look this this when done. (I’ve added some separators to provide notes and aid readability, they aren’t a requirement though so feel free to omit if you prefer).
Now we will create similar block rules on the VPN_WAN interface to prevent and log any unwanted ingress. Rules on the OpenVPN tab will apply before the interface tabs and also to all OpenVPN interfaces. I recommend creating specific and targeted interface rules so leave the OpenVPN interface clear.
Navigate to Firewall > Rules > VPN_WAN and create the following rules:
A rule to block and log IPv4 traffic
and a rule to block IPv6 traffic
Your VPN_WAN interface should look this this when done.
My management interface requirements are:
I’ve added some images in to help illustrate the correct way to complete the fields of the rule sheet.
Navigate to Firewall > Rules > VL10_MGMT and create the following rules:
Navigate to Firewall > NAT and select Port Forward
Click Add
Click Add
Navigate back to Firewall > Rules and select VL10_MGMT.
You should see two rules created for the redirects for NTP and DNS at the bottom. Now lets create the remaining rules for this subnet.
We identify traffic destined for the internet as to an interface which is NOT a LOCAL_SUBNETS.
Your VL10_MGMT interface should look this this when done.
Now we will create the rules for our VPN and primary local interface, the requirements for this interface are:
Navigate to Firewall > Rules > VL20_VPN and create the following rules.
Navigate to Firewall > NAT and select Port Forward
Click Add
Click Add
Navigate back to Firewall > Rules and select VL20_VPN.
You should see two rules created for the redirects for NTP and DNS at the bottom. Create the remaining rules for this subnet.
We make use of the LOCAL_SUBNETS and Allowed_OUT_Ports_LAN aliases in this rule
Allow specified traffic to egress via the default unencrypted ISP gateway. This is useful for sites which block VPNs or require you to expose your true location, for example, banking sites.
Block default IPv6
Your VL20_VPN interface should look this this when done.
Now we will create the rules for our unencrypted ‘clearnet’ local interface, the requirements for this interface are:
As clients perform DNS lookups on port 53 by default, we will create a port forward to forward traffic on VL30_CLRNET from port 53 to the Forwarder listening on localhost on port 5335.
Navigate to Firewall > NAT and select Port Forward
Click Add
Click Save & Apply changes
The redirect entry should look like this
Click Add
Click Add
Navigate back to Firewall > Rules and select VL30_CLRNET.
You should see three rules created for the redirects for NTP and DNS. Now let’s create the remaining rules for this subnet.
We make use of the Allowed_OUT_Ports_LAN & LOCAL_SUBNETS aliases here again.
Default block IPv6
Your VL30_CLRNET interface should look this this when done.
Our GUEST network is a special case. Critically, we do not allow guests access to access any internal devices or subnets. The requirements for the guest interface are:
Navigate to Firewall > Rules > VL40_GUEST and create the following rules:-
This_Firewall is an alias that represents all the interfaces on your pfSense box including VPNs, WANS etc.
This permits the external access including DNS/port 53 and NTP/port 123 traffic.
I also log any matches of this rule so I can see if any of my guests are attempting to access my local networks.
Default block IPv6
Your VL40_GUEST interface should look this this when done.
My LAN interface is treated rather differently. It’s mainly used for debugging and as such it can be reconfigured from time to time. As an initial setup I usually configure it with the following requirements in mind.
Navigate to Firewall > Rules > LAN and create the following rules:-
Create the anti-lockout rule ensuring we can always gain access to the GUI and the shell.
Default block IPv6
Your LAN interface should look this this when done.
This would be a good time to restart your firewall box and connect your modem to your WAN port if you haven’t already. The system should boot and allow you to log back into the dashboard where if everything is correct, the WAN and VPN_WAN interfaces will have IP addresses allocated to them.
If things don’t work as expected, make use of the system logs by navigating to Status > System Logs. The various tabs there will allow you to investigate all areas of the firewall and help you track down any issues.
Connect up your managed switch and assuming you have correctly configured the trunk port and tagged LAN ports you should be able to go ahead and test the various subnets work correctly. There are some switch configuration guides for popular and cheap models available from the index page.
Connect to each subnet in turn and verify a client receives an appropriate address from the associated DHCP pool. Heres the connection when connected to the VL20_VPN network where a 192.168.20.100 address has been awarded.
$ ifconfig en0
en0: flags=8963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether xx:xx:xx:xx:xx:xx
inet6 fe80::bae8:56ff:fe30:905e%en0 prefixlen 64 scopeid 0x4
inet 192.168.20.100 netmask 0xffffff00 broadcast 192.168.20.255
nd6 options=1<PERFORMNUD>
media: autoselect
status: active
We have three methods of DNS resolution to verify:
In these examples I’ll use ‘dig’ (domain information groper) command to resolve IP address.
$ dig pfsense.org
; <<>> DiG 9.10.6 <<>> pfsense.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20952
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.org. IN A
;; ANSWER SECTION:
pfsense.org. 261 IN A 208.123.73.69
;; Query time: 2 msec
;; SERVER: 192.168.20.1#53(192.168.20.1)
;; WHEN: Fri Mar 27 14:26:22 PDT 2020
;; MSG SIZE rcvd: 56
Use the dig command and force the DNS query to use Googles DNS server (8.8.8.8). This should be redirected back to the pfSense DNS resolver for lookup.
$ dig @8.8.8.8 pfsense.org
; <<>> DiG 9.10.6 <<>> @8.8.8.8 pfsense.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4847
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.org. IN A
;; ANSWER SECTION:
pfsense.org. 232 IN A 208.123.73.69
;; Query time: 2 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Mar 27 14:26:51 PDT 2020
;; MSG SIZE rcvd: 56
I use nslookup to lookup my pfSense gateway by its hostname and verify the address is returned correctly.
$ dig pfsense.local.lan
; <<>> DiG 9.10.6 <<>> pfsense.local.lan
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44388
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.local.lan. IN A
;; ANSWER SECTION:
pfsense.local.lan. 3600 IN A 192.168.1.1
;; Query time: 2 msec
;; SERVER: 192.168.20.1#53(192.168.20.1)
;; WHEN: Fri Mar 27 14:35:35 PDT 2020
;; MSG SIZE rcvd: 62
Verify you can resolve a hostname from an IP address
$ dig +noall +answer -x 192.168.1.1
1.1.168.192.in-addr.arpa. 3600 IN PTR pfSense.local.lan.
My DNS Resolver is defined as authoritative for my local.lan domain. If I try and lookup an address which is not part of my network, it will return status: NXDOMAIN
rather than forward the lookup to external DNS resolvers.
$ dig nothere.local.lan
; <<>> DiG 9.8.3-P1 <<>> nothere.local.lan
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 18955
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;nothere.local.lan. IN A
;; AUTHORITY SECTION:
local.lan. 10800 IN SOA pfsense.local.lan. root.local.lan. 1 3600 1200 604800 10800
;; Query time: 4 msec
;; SERVER: 192.168.20.1#53(192.168.20.1)
;; WHEN: Sun Aug 27 10:22:30 2017
;; MSG SIZE rcvd: 84
The server response is correctly displayed as 192.168.30.1
$ dig pfsense.org
; <<>> DiG 9.10.6 <<>> pfsense.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1174
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.org. IN A
;; ANSWER SECTION:
pfsense.org. 300 IN A 208.123.73.69
;; Query time: 230 msec
;; SERVER: 192.168.30.1#53(192.168.30.1)
;; WHEN: Fri Mar 27 14:58:08 PDT 2020
;; MSG SIZE rcvd: 56
Use the dig command and force the DNS query to use Googles DNS server (8.8.8.8). This should be redirected back to the pfSense DNS resolver for resolution. Dig is unable to correctly identify the true source of the name resolution and assumes it was a response from the target servers, in this example 8.8.8.8. The low query response time of 2 msec suggests that this wasn’t actually the case. More through testing is possible using a packet sniffer but this is beyond the scope opt this guide.
$ dig @8.8.8.8 pfsense.org
; <<>> DiG 9.10.6 <<>> @8.8.8.8 pfsense.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43195
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.org. IN A
;; ANSWER SECTION:
pfsense.org. 235 IN A 208.123.73.69
;; Query time: 2 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Fri Mar 27 14:59:12 PDT 2020
;; MSG SIZE rcvd: 56
This is handled by the forwarding rule to the DNS Resolver.
$ dig pfsense.local.lan
; <<>> DiG 9.10.6 <<>> pfsense.local.lan
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39629
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.local.lan. IN A
;; ANSWER SECTION:
pfsense.local.lan. 1 IN A 192.168.1.1
;; Query time: 2 msec
;; SERVER: 192.168.30.1#53(192.168.30.1)
;; WHEN: Fri Mar 27 15:00:22 PDT 2020
;; MSG SIZE rcvd: 62
Note the server resolving should be the DNS servers we configured in the General tab, in this example, 208.67.222.222
and not pfSense itself.
$ dig pfsense.org
; <<>> DiG 9.10.6 <<>> pfsense.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5451
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pfsense.org. IN A
;; ANSWER SECTION:
pfsense.org. 87 IN A 208.123.73.69
;; Query time: 17 msec
;; SERVER: 208.67.222.222#53(208.67.222.222)
;; WHEN: Fri Mar 27 15:01:40 PDT 2020
;; MSG SIZE rcvd: 56
Connect to the VL40_GUEST network and verify you can’t access the pfSense web configurator. Also verify you can’t access other systems and local devices you have connected to other subnets.
Open a browser and head over to AirVPN.org.
For the GUEST and CLRNET subnets you should observe your own IP address instead.
For the VPN subnet you should see a valid connection to a AirVPN server in the header bar.
It’s worth checking the crpyt selected as part of the connection process. Navigate to Status > System Logs and Select OpenVPN. Here’s a section from a successful connection with our intended data channel AES-256-GCM cipher.
OpenVPN 2.5.0 amd64-portbld-freebsd12.2 [SSL (OpenSSL)] [LZO] [LZ4] [MH/RECVDA] [AEAD] built on Feb 5 2021
library versions: OpenSSL 1.1.1i-freebsd 8 Dec 2020, LZO 2.10
MANAGEMENT: unix domain socket listening on /var/etc/openvpn/client1/sock
mlockall call succeeded
NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Initializing OpenSSL support for engine 'rdrand'
WARNING: experimental option --capath /var/etc/openvpn/client1/ca
Outgoing Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Outgoing Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Incoming Control Channel Encryption: Cipher 'AES-256-CTR' initialized with 256 bit key
Incoming Control Channel Encryption: Using 256 bit message hash 'SHA256' for HMAC authentication
Control Channel MTU parms [ L:1621 D:1156 EF:94 EB:0 ET:0 EL:3 ]
Data Channel MTU parms [ L:1621 D:1450 EF:121 EB:406 ET:0 EL:3 ]
Local Options String (VER=V4): 'V4,dev-type tun,link-mtu 1601,tun-mtu 1500,proto UDPv4,cipher AES-256-CBC,auth SHA512,keysize 256,key-method 2,tls-client'
Expected Remote Options String (VER=V4): 'V4,dev-type tun,link-mtu 1601,tun-mtu 1500,proto UDPv4,cipher AES-256-CBC,auth SHA512,keysize 256,key-method 2,tls-server'
TCP/UDP: Preserving recently used remote address: [AF_INET]199.249.223.132:443
Socket Buffers: R=[42080->524288] S=[57344->524288]
UDPv4 link local (bound): [AF_INET]xxx.xxx.xxx.xxx:0
UDPv4 link remote: [AF_INET]199.249.223.132:443
TLS: Initial packet from [AF_INET]199.249.223.132:443, sid=2bdb5ead 8890b169
VERIFY WARNING: depth=0, unable to get certificate CRL: C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=Aquila, emailAddress=info@airvpn.org
VERIFY WARNING: depth=1, unable to get certificate CRL: C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=airvpn.org CA, emailAddress=info@airvpn.org
VERIFY OK: depth=1, C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=airvpn.org CA, emailAddress=info@airvpn.org
VERIFY KU OK
Validating certificate extended key usage
++ Certificate has EKU (str) TLS Web Server Authentication, expects TLS Web Server Authentication
VERIFY EKU OK
VERIFY OK: depth=0, C=IT, ST=IT, L=Perugia, O=airvpn.org, CN=Aquila, emailAddress=info@airvpn.org
WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1601', remote='link-mtu 1602'
WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo'
Control Channel: TLSv1.3, cipher TLSv1.3 TLS_CHACHA20_POLY1305_SHA256, 4096 bit RSA
[Aquila] Peer Connection Initiated with [AF_INET]199.249.223.132:443
PUSH: Received control message: 'PUSH_REPLY,comp-lzo no,redirect-gateway def1 bypass-dhcp,dhcp-option DNS 10.9.190.1,route-gateway 10.9.190.1,topology subnet,ping 10,ping-restart 60,ifconfig 10.9.190.15 255.255.255.0,peer-id 2,cipher AES-256-GCM'
OPTIONS IMPORT: timers and/or timeouts modified
OPTIONS IMPORT: compression parms modified
OPTIONS IMPORT: --ifconfig/up options modified
OPTIONS IMPORT: route options modified
OPTIONS IMPORT: route-related options modified
OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified
OPTIONS IMPORT: peer-id set
OPTIONS IMPORT: adjusting link_mtu to 1624
OPTIONS IMPORT: data channel crypto options modified
Data Channel: using negotiated cipher 'AES-256-GCM'
Data Channel MTU parms [ L:1552 D:1450 EF:52 EB:406 ET:0 EL:3 ]
Outgoing Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
Incoming Data Channel: Cipher 'AES-256-GCM' initialized with 256 bit key
ROUTE_GATEWAY xxx.xxx.xxx.xxx/255.255.248.0 IFACE=ixl1 HWADDR=xx:xx:xx:df:09:ed
TUN/TAP device ovpnc1 exists previously, keep at program end
TUN/TAP device /dev/tun1 opened
do_ifconfig, ipv4=1, ipv6=0
/sbin/ifconfig ovpnc1 10.9.190.15 10.9.190.1 mtu 1500 netmask 255.255.255.0 up
/sbin/route add -net 10.9.190.0 10.9.190.1 255.255.255.0
/usr/local/sbin/ovpn-linkup ovpnc1 1500 1552 10.9.190.15 255.255.255.0 init
Initialization Sequence Completed
Open a browser and head over to DNSLeaktest.com.
To validate functionality run an extended leak test on each subnet. If you find the test doesn’t start correctly, disable ‘Experimental Bit 0x20 Support’ under the DNS Resolver’s advanced settings and try again.
It’s important to verify that the VL20_VPN subnet isn’t leaking and only identifies a single DNS server resolved via an AirVPN end point.
My VL30_CLRNET subnet shows several OpenDNS servers as configured under the general configuration tab. As the DNS Resolver is enabled as a DNS server for the firewall, 127.0.0.1 will be added to the list of servers queried and this is why you will notice a lookup served via the VPN tunnel also.
My VL40_GUEST network as expected shows up multiple ISP servers.
VPN performance will depend on your hardware and also fluctuate depending on server load especially during peak times. With a nearby server I would look for a 15ms increase in ping times and a reduction in throughput of around 10% of the hardware capabilities.
I validated performance with speedtest.net.
Here’s my LAN performance illustrating Verizon’s FIOS 150/150 service performance.
and here’s my VL20_VPN performance
pfSense documentation
pfSense book
CIDR notation
RFC1918
27 February 2021
Minor additions for clarity
20 February 2021
Revised for pfSense v2.5.0
25 June 2020
Additional network interface configuration details added
20 April 2020
Added reference link to pfBlockerNG guide
13 April 2020
Added further DNS Resolver details
Updated DNS leak test results
1 April 2020
Corrected typos, added some additional details.
28 March 2020
Corrected typos
27 March 2020
Major Revision for pfSense v2.4.5
28 January 2018
Added link to SG300 switch guide
11 December 2017
Fixed typos & inconsistencies in images
25 November 2017
Misc typo’s fixed
2 November 2017
Added Unifi guide link
Correct error in VL10_MGMT interface image
Fixed DNS leak test link
29 August 2017
Updated destination field in DNS port forward
Updated strict interface binding setting in DNS Forwarder