Running pfSense as an Azure IaaS Virtual Machine

23 Jul

A client of mine has asked me if it would be possible to run pfSense as a Microsoft Azure IaaS Virtual Machine. pfSense® software is a free, open source customized distribution of FreeBSD, specifically tailored for use as a firewall and router that is entirely managed via web interface.

At that time, I had in mind that running FreeBSD 10 under Hyper-V and in Microsoft Azure, is something that can be done. So, I decided to build a deployment as a Proof of Concept and to write a blog post about this deployment.

This post will provide instructions and all the necessary steps to prepare, upload and run pfSense-2.2.3 in Microsoft Azure.

Please note, that FreeBSD is not currently an endorsed distribution in Microsoft Azure and therefore is not supported.


Let’s put, what we want to achieve, into context. The deployment’s design is as follows:



In order to prepare a pfSense image for Microsoft Azure, we should download the latest x64 image and install it locally, on a server with Windows Server 2012 R2, as a Hyper-V Virtual Machine:

  1. Download the latest x64 pfSense image from Latest Stable Version of pfSense (As of July 2015 the latest version is 2.2.3)
  2. Decompress the image file to extract the Installation ISO pfSense-LiveCD-2.2.3-RELEASE-amd64-20150623-1637.iso
  3. Attach the ISO file as a DVD Drive to newly created Hyper-V Virtual Machine


  1. Start the installation of pfSense


  • After successful installation of pfSense, enable SSH


  • Install Python 2.7 and required modules
[2.2.3-RELEASE][[email protected]]/: pkg install python27 py27-asn1
Updating FreeBSD repository catalogue...
FreeBSD repository is up-to-date.
All repositories are up-to-date.
Checking integrity... done (0 conflicting)
The following 3 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        python27: 2.7.10
        py27-asn1: 0.1.7,1
        py27-setuptools27: 17.0

The process will require 67 MiB more space.

Proceed with this action? [y/N]: y
[1/3] Installing python27-2.7.10...
[1/3] Extracting python27-2.7.10: 100%
[2/3] Installing py27-setuptools27-17.0...
[2/3] Extracting py27-setuptools27-17.0: 100%
[3/3] Installing py27-asn1-0.1.7,1...
[3/3] Extracting py27-asn1-0.1.7,1: 100%
Message for python27-2.7.10:

Note that some standard Python modules are provided as separate ports
as they require additional dependencies. They are available as:

bsddb           databases/py-bsddb
gdbm            databases/py-gdbm
sqlite3         databases/py-sqlite3
tkinter         x11-toolkits/py-tkinter

[2.2.3-RELEASE][[email protected]]/:

You should symlink the new python 2.7 binary

[2.2.3-RELEASE][[email protected]]/: ln -s /usr/local/bin/python2.7 /usr/bin/python
  •  Install sudo

Typically on Azure, root account is disabled and we using uprovileged user to login. An unprivileged user should utilize sudo to run commands with elevated privileges.

[2.2.3-RELEASE][[email protected]]/: pkg install sudo
Updating FreeBSD repository catalogue...
FreeBSD repository is up-to-date.
All repositories are up-to-date.
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        sudo: 1.8.14

The process will require 3 MiB more space.
796 KiB to be downloaded.

Proceed with this action? [y/N]: y
Fetching sudo-1.8.14.txz: 100%  796 KiB 815.0kB/s    00:01
Checking integrity... done (0 conflicting)
[1/1] Installing sudo-1.8.14...
[1/1] Extracting sudo-1.8.14: 100%
[2.2.3-RELEASE][[email protected]]/:
  •  Install the Azure Linux Agent

GitHub is the repository where you can find the latest version of Azure Linux Agent

Version 2.0.10 or later is required for FreeBSD. Branch 2.0 is typically very stable and as of July 2015 the latest version is 2.0.14.

[2.2.3-RELEASE][[email protected]]/: wget
--2015-07-23 13:25:16--
Resolving (
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 245087 (239K) [text/plain]
Saving to: 'waagent'

waagent                         100%[======================================================>] 239.34K   624KB/s   in 0.4s

2015-07-23 13:25:17 (624 KB/s) - 'waagent' saved [245087/245087]

[2.2.3-RELEASE][[email protected]]/: mv ./waagent /usr/sbin/
[2.2.3-RELEASE][[email protected]]/: chmod 755 /usr/sbin/waagent
[2.2.3-RELEASE][[email protected]]/: /usr/sbin/wa
[2.2.3-RELEASE][[email protected]]/: /usr/sbin/waagent -install
[2.2.3-RELEASE][[email protected]]/:
  • Set IP Addresses

Configure WAN (hn0) Interface as DHCP client.

Assign Static IP Address,, to LAN (hn1) Interface


  •  Shutdown The pfSense Virtual Machine

Now the pfSense Virtual Machine is ready for running in Microsoft Azure.

Upload the pfSense-2.3.3 VHD to Azure

Using the following PowerShell commands, first we upload the pfSense VHD to Microsoft Azure Storage Account and then we create a custom image:

# Variables Section
$DestFile = ""
$SourceFile = "C:\Hyper-V\pfSense\Virtual Hard Disks\pfSense-2-2-3.vhd"

# VHD Upload
Add-AzureVhd -Destination $DestFile -LocalFilePath $SourceFile
# Create an Image
Add-AzureVMImage -ImageName "pfSense-2.2.3" -MediaLocation $DestFile -OS Linux

Note that we are using OS type Linux instead of FreeBSD as it is not currently supported.

Create a Multi-NIC Virtual Machine

The custom image that we created previously, can be used in order to create a pfSense Virtual Machine with two Virtual Network Interfaces (vNIC), in Microsoft Azure. More details about creating a Virtual Machine with Multiple vNICs in Microsoft Azure, you can find in a previous post here:

Create a Virtual Machine with Multiple NICs in Azure IaaS

A pfSense Virtual Machine with two vNICs will be created by running the following PowerShell commands:

$location = "West Europe"
$serviceName = "pfsvc"
$vnet = "pf-VNET"
$subscriptionName = 'My MSDN Subscription'
$storageAccount = 'pfsa'
$adminUser = "adminuser"
$pwd = "*********"
$imageName = "pfSense-2.2.3"

$MultiVM = New-AzureVMConfig -ImageName $ImageName `
	   -Name "pfSense-FW01" -InstanceSize ExtraLarge |
       Add-AzureProvisioningConfig -Linux -LinuxUser $adminUser `
	   -Password $pwd |
       Set-AzureSubnet -SubnetNames "Front-End" |
       Set-AzureStaticVNetIP -IPAddress "" |
       Add-AzureNetworkInterfaceConfig -Name "LAN NIC" `
	   -SubnetName "LAN-Subnet" -StaticVNetIPAddress

New-AzureVM -ServiceName $serviceName `
            -Location $location `
            -VNetName $vnet `
            -VMs $MultiVM
Setup User Defined Routes

With user defined routes, we have complete control over the traffic flow in our virtual network. Virtual network by default provides system routes for traffic flow between virtual machines. Now, we can customize the routing table by defining routes and that is allowing us to direct traffic through pfSense Virtual Machine that we have just created. Routes can be defined inside a routing table and applied to subnets. Every VM within a subnet automatically inherits the routes from the routing table.

The following PowerShell commands, allowing us to:

  • Create the routing tables
  • Create routes in the routing tables
  • Apply routing tables to subnets
  • Enable IP Forwarding on pfSense’s vNICs
# Variables Section
$Location="West Europe"
$ServiceName = "pfsvc"
$VM = Get-AzureVM -Name "pfSense-FW01" -ServiceName $serviceName

# Set the route table of the Frontend network:
$FrontRT = New-AzureRouteTable -Name $FrontendName `
		-Location $Location -Label "FE-RT"
Set-AzureRoute -RouteTable $FrontRT -RouteName "DMZ-Route" `
		-AddressPrefix "" -NextHopType "VirtualAppliance" `
		-NextHopIpAddress ""
Set-AzureSubnetRouteTable -VirtualNetworkName $VNetName `
		-SubnetName $FrontendName -RouteTableName $FrontendName

# Set the route table of the LAN network:
$LANRT = New-AzureRouteTable -Name $LANName `
		-Location $Location -Label "LAN-RT"
Set-AzureRoute -RouteTable $LANRT -RouteName "FE-Route" `
		-AddressPrefix -NextHopType VirtualAppliance `
Set-AzureRoute -RouteTable $LANRT -RouteName default -AddressPrefix `
		-NextHopType VirtualAppliance -NextHopIpAddress
Set-AzureSubnetRouteTable -VirtualNetworkName $VNetName -SubnetName $LANName `
		-RouteTableName $LANName

# Enable IP Forwarding on the main NIC and secondary NICs:
Set-AzureIPForwarding -ServiceName $ServiceName -VM $VM -Enable
Set-AzureIPForwarding -ServiceName $ServiceName -VM $VM `
		-NetworkInterfaceName "LAN NIC" -Enable

The pfSense Virtual Machines must be able to receive incoming traffic that is not addressed to itself and this is the reason to enable IP forwarding.

12 Replies to “Running pfSense as an Azure IaaS Virtual Machine

  1. I noticed the twitter post saying the pfsense say there are some serious shortcomings with this setup; do you know what these are and are they insurmountable and should we wait for the official image?

  2. I didn’t notice any serious or insurmountable shortcomings. This procedure has led to a production environment, that is working perfectly until now. However, an official image that is engineered by Microsoft and pfSense teams together is always better.

  3. Do you have any information on setting up the load balancer to forward all traffic instead of having to build a million NAT rules from Public IP > Front end IP of PF sense followed by the same rules passing traffic to the server vnet?

    hope that makes sense

    • Azure Load Balancer will do port translation and load balance the network traffic, by leveraging the public IP address for the cloud service.

      In the classic deployment model, port translation is done through endpoints that have a one-to-one relationship between the public assigned port of the public IP address and the local port assigned to send traffic to a specific virtual machine.

      Another way to access an Azure VM is the Instance Level Public IP (ILPIP) which is a public IP address that you can assign directly to your VM or role instance, rather than to the cloud service that your VM or role instance reside in. Please keep in mind that ILPIP is an IP directly assigned to an Azure VM without any protection like firewall, DDOS etc.

  4. Thank You Vaggelis for this. What I mean is I have to create a NAT rule for every port I want to be allow to access PF Sense. I.e I cant say Port Range * to Port Range * go to PF Sense DMZ NIC1

    IT has to be 1 rule at a time ie

    443 to DMZ NIC1
    51 to DMZ NIC 1 and so on

    Also having problems uploading the VHD

    setting this up is proving a challenge between the load balancer and assigning NICS etc

    • This is correct. You have to create an Endpoint for each port you want to forward to pfSense and then create a pfSense rule to allow the traffic to this port. Using Powershell for Endpoint creation will simplify the process on Azure side.

  5. The official PFSense version do not deploy correctly and with an A3 or D Series VM (to allow multiple NICs) the setup gets costly quick.

    @Vaggelis, would you mind to update the guide für the new Azure Portal / Azure Resource Manager? I am trying to follow your guide and using Input from here: but the PFSense VM is not spinning up. The HDD remains a 0 Byte disk and at the end the deployment times out.

    • Sure, actually is on my plans first to update the guide, in order to be valid for the Azure Resource Manager model and then to write a new blog post about how you can use a single NIC VM to protect your Azure Virtual Network.

  6. Hi,
    This is an excellent article.
    Unfortunately I am having issues installing the Azure Linux Agent as wget or fetch commands are unrecognized by pfsense. I am running the pfSense version 2.3.2 using Hyper V on Windows Server 2012. I was able to install python and sudo but azure linux agent has proved to be tricky. Any suggestions?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.