pfSense Community Edition (CE) is a free firewall and router distribution from Netgate. It is based on FreeBSD, so it cannot be installed as a package on Linux; the usual way to run it on a Linux machine is as a virtual machine. In this tutorial you will turn an Ubuntu 24.04 server into a KVM host with libvirt, create a WAN network and an isolated LAN network, install pfSense CE in a virtual machine, complete the setup wizard from your browser through an SSH tunnel and add your first firewall rule.

The lab uses libvirt's NAT network as the WAN. Once it works, you can attach the WAN to a bridge on a public interface instead, as described at the end.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS with hardware virtualization (Intel VT-x or AMD-V), for example a CubePath dedicated server. A VPS only works if its provider supports nested virtualization.
  • At least 2 CPU cores, 4 GB of RAM and 25 GB of free disk space on the host. The pfSense VM uses 2 GB of RAM and a 20 GB disk.
  • A non-root user with sudo privileges.
  • A free Netgate account to download the installer, and a VNC viewer and SSH client on your workstation.

Step 1 - Installing KVM and libvirt

First, confirm that the CPU exposes virtualization extensions to the host:

sudo apt update
sudo apt install cpu-checker
kvm-ok
INFO: /dev/kvm exists
KVM acceleration can be used

If kvm-ok reports that KVM acceleration cannot be used, enable virtualization in the BIOS/UEFI, or use a machine that supports it.

Install QEMU, the libvirt daemon and virt-install:

sudo apt install qemu-system-x86 qemu-utils libvirt-daemon-system libvirt-clients virtinst

Add your user to the libvirt group so you can manage VMs, then log out and back in for the change to take effect:

sudo usermod -aG libvirt "$USER"

Check that libvirt is running and that its default NAT network is active:

sudo systemctl status libvirtd --no-pager
virsh --connect qemu:///system net-list --all
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

The default network gives guests addresses in 192.168.122.0/24 and NATs them to the Internet through the host. It will be the pfSense WAN.

Step 2 - Creating the isolated LAN network

pfSense needs a second network for the LAN side. Create an isolated libvirt network: it has no DHCP server and no route to the outside, so all traffic from it must pass through pfSense. The host gets the address 192.168.1.2 on it, which you will use to reach the pfSense web interface.

Create the network definition:

nano ~/pflan.xml
<network>
  <name>pflan</name>
  <bridge name="virbr-pflan" stp="on" delay="0"/>
  <ip address="192.168.1.2" netmask="255.255.255.0"/>
</network>

There is no <forward> element, which makes the network isolated, and no <dhcp> element, because pfSense will be the DHCP server for the LAN. Define it, start it and mark it to start at boot:

virsh --connect qemu:///system net-define ~/pflan.xml
virsh --connect qemu:///system net-start pflan
virsh --connect qemu:///system net-autostart pflan
ip -brief address show virbr-pflan
virbr-pflan      DOWN           192.168.1.2/24

The bridge shows DOWN until a VM is attached to it.

Step 3 - Downloading the pfSense installer

Netgate distributes pfSense CE through the Netgate Installer, an ISO that downloads the current release during installation. Sign in to the Netgate store, add the free pfSense CE installer for AMD64 to the cart, check out at no cost and copy the download link. Download it on the server into the libvirt image directory, replacing download_url with your link:

cd /tmp
curl -fL -o netgate-installer-amd64.iso.gz 'download_url'

If the file is compressed (.gz), decompress it and move it into place:

gunzip netgate-installer-amd64.iso.gz
sudo mv netgate-installer-amd64.iso /var/lib/libvirt/images/

Compare the checksum with the one shown on the download page:

sha256sum /var/lib/libvirt/images/netgate-installer-amd64.iso

Step 4 - Creating the virtual machine

Create the VM with two virtio network cards. The first is attached to default (WAN) and the second to pflan (LAN). pfSense names virtio interfaces vtnet0 and vtnet1 in that order:

sudo virt-install \
  --name pfsense \
  --memory 2048 \
  --vcpus 2 \
  --os-variant freebsd14.0 \
  --disk path=/var/lib/libvirt/images/pfsense.qcow2,size=20,format=qcow2,bus=virtio \
  --cdrom /var/lib/libvirt/images/netgate-installer-amd64.iso \
  --network network=default,model=virtio \
  --network network=pflan,model=virtio \
  --graphics vnc,listen=127.0.0.1 \
  --noautoconsole

If virt-install does not know freebsd14.0, list the FreeBSD variants your version knows with osinfo-query os | grep -i freebsd and use the newest one.

The VNC console only listens on the host's loopback address, so it is not exposed to the Internet. Find its display number:

virsh --connect qemu:///system vncdisplay pfsense
127.0.0.1:0

Display :0 is TCP port 5900 (:1 would be 5901). From your workstation, open an SSH tunnel to that port:

ssh -L 5900:127.0.0.1:5900 your_user@your_server_ip

Keep the session open and connect your VNC viewer to localhost:5900. You should see the installer booting.

Step 5 - Installing pfSense

The Netgate Installer needs Internet access through the WAN to download packages. Follow the prompts:

  1. Accept the copyright and distribution notice.
  2. Choose Install pfSense.
  3. For the WAN interface select vtnet0 and keep DHCP. It will receive an address from libvirt in 192.168.122.0/24.
  4. For the LAN interface select vtnet1 and keep the default address 192.168.1.1/24.
  5. Continue with the connectivity check. The installer confirms that it can reach Netgate's servers.
  6. Select Install CE (the free edition) and accept the default ZFS layout on the single vtbd0 disk.
  7. When the installation finishes, choose to reboot.

virt-install boots from the ISO only for the installation run, and the stored VM definition boots from the disk. Depending on your libvirt version, the VM either reboots into pfSense or powers off at this point. Check its state on the host:

virsh --connect qemu:///system list --all

If pfsense is shut off, start it and reconnect your VNC viewer:

virsh --connect qemu:///system start pfsense

Once pfSense has booted, the VNC console shows the pfSense console menu with the interface summary:

WAN (wan)       -> vtnet0     -> v4/DHCP4: 192.168.122.57/24
LAN (lan)       -> vtnet1     -> v4: 192.168.1.1/24

 0) Logout / Disconnect SSH            9) pfTop
 1) Assign Interfaces                 10) Filter Logs
 2) Set interface(s) IP address       11) Restart GUI
 3) Reset admin account and password  12) PHP shell + pfSense tools
 4) Reset to factory defaults         13) Update from console
 5) Reboot system                     14) Enable Secure Shell (sshd)
 6) Halt system                       15) Restore recent configuration
 7) Ping host                         16) Restart PHP-FPM
 8) Shell

If WAN and LAN are swapped, use option 1 to reassign them. Make the VM start with the host:

virsh --connect qemu:///system autostart pfsense

From the host, confirm that the LAN address answers:

ping -c 3 192.168.1.1

Step 6 - Running the setup wizard

The web interface (webConfigurator) is only reachable from the LAN. Since the host has 192.168.1.2 on that network, forward a local port through SSH. On your workstation, open a second tunnel:

ssh -L 8443:192.168.1.1:443 your_user@your_server_ip

Browse to https://localhost:8443, accept the self-signed certificate warning and log in with the default credentials, user admin and password pfsense. The setup wizard starts automatically. Work through it:

  1. General Information: set a hostname (for example fw01), a domain and, optionally, DNS servers such as 1.1.1.1 and 9.9.9.9.
  2. Time Server: keep the default NTP pool and select your time zone.
  3. Configure WAN Interface: keep DHCP. At the bottom, uncheck Block RFC1918 Private Networks, because in this lab the WAN itself is a private network (192.168.122.0/24). Leave it checked when the WAN has a public address.
  4. Configure LAN Interface: keep 192.168.1.1/24.
  5. Set Admin WebGUI Password: enter a strong password. This replaces the default pfsense password.
  6. Reload the configuration and finish the wizard.

Log in again with the new password. The dashboard shows the pfSense version, the interfaces and their addresses.

Step 7 - Updating pfSense and adding a firewall rule

Go to System > Update, confirm that the branch is the latest stable release and install any pending update. The firewall reboots if the update requires it.

pfSense ships with a default rule set: on the LAN, an "anti-lockout" rule and a rule that allows the LAN to reach any destination; on the WAN, everything unsolicited is blocked. Rules are evaluated per interface from top to bottom, and the first match wins.

As an example, restrict the LAN so that clients can only use the pfSense DNS resolver instead of any external DNS server. Go to Firewall > Rules > LAN and click the Add button with the up arrow to place the rule at the top:

  • Action: Block
  • Interface: LAN
  • Address Family: IPv4+IPv6
  • Protocol: TCP/UDP
  • Source: LAN subnets
  • Destination: Invert match checked, This Firewall (self)
  • Destination Port Range: DNS (53)
  • Log packets that are handled by this rule: checked
  • Description: Block external DNS from LAN

Click Save, then Apply Changes. To verify it, attach a client to the pflan network (any VM with its network set to network=pflan), then run dig @1.1.1.1 example.com on it. The query times out, while dig @192.168.1.1 example.com works. The blocked attempts appear in Status > System Logs > Firewall with the rule description.

Step 8 - Backing up the configuration

pfSense stores its whole configuration in a single XML file. Download a copy from Diagnostics > Backup & Restore by clicking Download configuration as XML, and keep it outside the firewall. Restoring that file on a fresh installation brings back every rule, interface and setting.

For a full rollback point before upgrades, you can also take a snapshot of the VM from the host:

virsh --connect qemu:///system snapshot-create-as pfsense pre-upgrade "Before pfSense upgrade"
virsh --connect qemu:///system snapshot-list pfsense
 Name          Creation Time               State
---------------------------------------------------
 pre-upgrade   2026-09-25 11:20:04 +0000   running

Moving the WAN to a public interface

In production the WAN is usually connected to a Linux bridge on the host's public network card, and pfSense uses a public IP address directly. This requires an additional public IP that your provider routes to the VM (often tied to a specific MAC address), and a host bridge created with Netplan. Change the VM's first interface from network=default to bridge=br0 with virsh edit pfsense, then set the WAN address in pfSense under Interfaces > WAN. Do this from an out-of-band console, because a mistake in the host's Netplan configuration can cut your SSH access.

Troubleshooting

  • kvm-ok fails on a VPS. The hypervisor does not expose nested virtualization. Use a dedicated server.
  • The installer's connectivity check fails. Confirm that the default network is active on the host and that the WAN interface is vtnet0 with a DHCP address in 192.168.122.0/24.
  • The web interface does not load through the tunnel. Check that the host reaches 192.168.1.1 with ping, and that you used https. If you changed the LAN address in the wizard, update the tunnel destination.
  • The VM boots the installer again after installing. The ISO is still attached and first in the boot order. Find the CD-ROM target with virsh --connect qemu:///system domblklist pfsense (usually sda), eject it with virsh --connect qemu:///system change-media pfsense sda --eject --config, then shut the VM down and start it again.

Conclusion

You now have pfSense CE running as a KVM virtual machine on Ubuntu 24.04, with a WAN on libvirt's NAT network, an isolated LAN protected by the firewall, a first custom rule and a backup of the configuration. From here you can add VLAN interfaces for network segmentation, set up a WireGuard or OpenVPN remote access VPN under VPN, or install packages such as pfBlockerNG or Suricata from System > Package Manager.