This comprehensive guide demonstrates how to create custom Virtual Hard Disks (VHDs), configure them with the PFSense network appliance, and deploy them in Microsoft Azure. We'll cover the complete workflow from VM creation through image management and deployment.
In this tutorial, we'll:
When creating a virtual machine in Azure:
Before starting the VM, we need to configure additional resources:
Add Additional Disk:
Add Network Interface:
Connect via PuTTY (SSH) and execute the following commands:
# Update packages
pkg upgrade -y
# Fix Perl symlink
ln -sf /usr/local/bin/perl /usr/bin/perl
# Install bash and git
pkg install bash git -y
# Search for Python packages
pkg search python
pkg search setuptools
# Install Python 2.7 (if using legacy setup)
pkg install python27-2.7.14_1 py27-setuptools-36.5.0
# Create Python symlink
ln -sf /usr/local/bin/python2.7 /usr/local/bin/python
# Install Azure WALinuxAgent
git clone https://github.com/Azure/WALinuxAgent.git
cd WALinuxAgent
python setup.py install
# Create WALinuxAgent symlink
ln -sf /usr/local/sbin/waagent /usr/local/bin/waagent
# Verify agent installation
waagent -version
Check that the WALinuxAgent is running properly:
# Check agent status
waagent -show-configuration
# The agent should be running and responsive
Configure the network interfaces for proper DHCP operation:
Before creating a VM image:
# Shutdown the VM
shutdown -p now
# Remove snapshots (via Azure Portal)
# This ensures a clean state for image capture
First, authenticate with Azure:
# Connect to Azure
Connect-AzureRmAccount
# Define variables
$ResourceGroupName = "RG_CORE_INFRA"
$pfresourcegroup = "RG_CORE_INFRA"
$StorageAccountName = "rgmouraddemov0"
$vnetname = "VNET_CORE_INFRA"
$location = "West Europe"
# Create storage account
New-AzureRmStorageAccount `
-ResourceGroupName $ResourceGroupName `
-Name $StorageAccountName `
-Location $location `
-SkuName "Standard_LRS" `
-Kind "Storage"
# Define variables
$rgName = "RG_CORE_INFRA"
$urlOfUploadedImageVhd = "https://rgmouraddemov0.blob.core.windows.net/vhd/pfsenseappliancevhd.vhd"
$localVhdPath = "C:\pfsense_appliance_demo_vhd.vhd"
# Upload VHD (this may take considerable time)
Add-AzureRmVhd `
-ResourceGroupName $rgName `
-Destination $urlOfUploadedImageVhd `
-LocalFilePath $localVhdPath
Note: VHD uploads can take 15-30+ minutes depending on size and connection speed. Be patient and keep the terminal active.
This PowerShell script creates a VM with dual NICs and public IPs:
# Define variables
$ResourceGroupName = "RG_CORE_INFRA"
$pfresourcegroup = "RG_CORE_INFRA"
$StorageAccountName = "rgmouraddemov0"
$vnetname = "VNET_CORE_INFRA"
$location = "West Europe"
# Get network resources
$vnet = Get-AzureRmVirtualNetwork `
-Name $vnetname `
-ResourceGroupName $ResourceGroupName
$backendSubnet = Get-AzureRmVirtualNetworkSubnetConfig `
-Name "default" `
-VirtualNetwork $vnet
# Define VM parameters
$vmName = "ROUTER-PFSENSE"
$DiskNameOfVm = "pfsenseos"
$vmSize = "Standard_DS2_v2"
# Create public IPs
$pubipwan = New-AzureRmPublicIpAddress `
-Name "PFPubIP-WAN" `
-ResourceGroupName $pfresourcegroup `
-Location $location `
-AllocationMethod Dynamic
$pubiplanadmin = New-AzureRmPublicIpAddress `
-Name "PFPubIP-LAN-ADMIN" `
-ResourceGroupName $pfresourcegroup `
-Location $location `
-AllocationMethod Dynamic
# Create network interfaces
$nic1 = New-AzureRmNetworkInterface `
-Name "PFIntNIC-LAN" `
-ResourceGroupName $pfresourcegroup `
-Location $location `
-SubnetId $vnet.Subnets[0].Id `
-PublicIpAddressId $pubiplanadmin.Id
$nic2 = New-AzureRmNetworkInterface `
-Name "PFIntNIC-WAN" `
-ResourceGroupName $pfresourcegroup `
-Location $location `
-SubnetId $vnet.Subnets[0].Id `
-PublicIpAddressId $pubipwan.Id
# Create VM configuration
$vm = New-AzureRmVMConfig -VMName $vmName -VMSize $vmSize
# Attach OS disk from blob
$vm = Set-AzureRmVMOSDisk `
-VM $vm `
-Name $DiskNameOfVm `
-VhdUri "https://rgmouraddemov0.blob.core.windows.net/vhd/pfsenseappliancevhdv1.vhd" `
-CreateOption Attach `
-Linux `
-Caching ReadWrite
# Add network interfaces
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic1.Id
$vm = Add-AzureRmVMNetworkInterface -VM $vm -Id $nic2.Id
# Configure boot diagnostics
Set-AzureRmVMBootDiagnostics `
-VM $vm `
-Enable `
-ResourceGroupName $ResourceGroupName `
-StorageAccountName $StorageAccountName
# Set primary NIC
$vm.NetworkProfile.NetworkInterfaces.Item(0).Primary = $true
# Create the VM
New-AzureRmVM `
-ResourceGroupName $pfresourcegroup `
-Location $location `
-VM $vm
After deployment (wait 5 minutes for full initialization):
# Define variables
$location = "west europe"
$imageName = "PFSENSE-IMAGE"
$ResourceGroupName = "RG_CORE_INFRA"
$osVhdUri = "https://rgmouraddemov0.blob.core.windows.net/vhd/pfsenseappliancevhd1.vhd"
# Create image configuration
$imageConfig = New-AzureRmImageConfig -Location $location
# Set OS disk properties
$imageConfig = Set-AzureRmImageOsDisk `
-Image $imageConfig `
-OsType Linux `
-OsState Generalized `
-BlobUri $osVhdUri
# Create the image
$image = New-AzureRmImage `
-ImageName $imageName `
-ResourceGroupName $ResourceGroupName `
-Image $imageConfig
Azure CLI provides a more straightforward approach for multi-NIC deployments:
# Define credentials
AdminPassword="MySecurePassword123!"
# Create first network interface (DMZ/WAN)
az network nic create \
--resource-group RG_CORE_INFRA \
--name pf-sense-nva-1-nic-1 \
--vnet-name vnet_core \
--subnet subnet_DMZ \
--ip-forwarding true \
--private-ip-address 10.1.1.37
# Create second network interface (LAN/Core)
az network nic create \
--resource-group RG_CORE_INFRA \
--name pf-sense-nva-1-nic-2 \
--vnet-name vnet_core \
--subnet subnet_core \
--ip-forwarding true \
--private-ip-address 10.1.1.53
# Create VM from image with both NICs
az vm create \
--resource-group RG_CORE_INFRA \
--name pf-sense-nva-1 \
--admin-username demo \
--admin-password $AdminPassword \
--nics pf-sense-nva-1-nic-2 pf-sense-nva-1-nic-1 \
--image PFSENSE-IMAGE \
--size Standard_DS2_v2 \
--os-disk-size-gb 32
# Enable boot diagnostics
az vm boot-diagnostics enable \
--resource-group RG_CORE_INFRA \
--name pf-sense-nva-1 \
--storage https://rgmouraddemov0.blob.core.windows.net
While PowerShell is powerful, the Azure Portal is more user-friendly for creating VMs from images with multiple NICs:
pfsenseappliancevhdv1.vhd)| Scenario | VM Size | vCPUs | RAM | Cost |
|---|---|---|---|---|
| Development | Standard_B2s | 2 | 4GB | Low |
| Small Production | Standard_D2s_v3 | 2 | 8GB | Medium |
| Production | Standard_DS2_v2 | 2 | 7GB | Medium-High |
| High-Performance | Standard_D4s_v3 | 4 | 16GB | High |
# Check disk usage
df -h
# Monitor network interfaces
netstat -i
# View system logs
tail -f /var/log/messages
# Check Azure agent logs
cat /var/log/waagent.log
pkg upgrade -y)Solution: Enable boot diagnostics during VM creation. Use the serial console for troubleshooting:
# Check kernel logs
dmesg | tail -20
# Check system status
systemctl status waagent
Solution: Ensure IP forwarding is enabled and properly configured:
# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1
# Verify configuration
sysctl net.ipv4.ip_forward
Solution:
Add-AzureRmVhd with parallel uploads for multiple filesCreate reusable deployment scripts:
#!/bin/bash
# deploy-pfsense-vm.sh
RESOURCE_GROUP="RG_CORE_INFRA"
VM_NAME="pf-sense-nva-$1"
IMAGE_NAME="PFSENSE-IMAGE"
VNET_NAME="vnet_core"
# Create NICs
az network nic create \
--resource-group $RESOURCE_GROUP \
--name ${VM_NAME}-nic-1 \
--vnet-name $VNET_NAME \
--subnet subnet_DMZ \
--ip-forwarding true
az network nic create \
--resource-group $RESOURCE_GROUP \
--name ${VM_NAME}-nic-2 \
--vnet-name $VNET_NAME \
--subnet subnet_core \
--ip-forwarding true
# Create VM
az vm create \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--nics ${VM_NAME}-nic-2 ${VM_NAME}-nic-1 \
--image $IMAGE_NAME
Usage:
./deploy-pfsense-vm.sh 1 # Creates pf-sense-nva-1
./deploy-pfsense-vm.sh 2 # Creates pf-sense-nva-2
Maintain multiple image versions:
# List all images
az image list --resource-group RG_CORE_INFRA
# Delete old image
az image delete \
--resource-group RG_CORE_INFRA \
--name PFSENSE-IMAGE-v1
# Create tagged versions
az image create \
--name PFSENSE-IMAGE-2024-05 \
--resource-group RG_CORE_INFRA \
...
This guide provides a complete workflow for deploying custom-configured PFSense network appliances in Azure. The flexibility of using custom VHDs and images enables reproducible, scalable deployments for complex networking scenarios.
Key Takeaways:
Reference: Based on guidance from e-apostolidis.gr/microsoft/azure/custom-pfsense-on-azurerm-a-complete-guide/
PFSense provides enterprise-grade routing and firewalling capabilities. Combined with Azure's infrastructure flexibility, it creates powerful, customizable network topologies for complex cloud architectures.