Jesse A. Green / notebook

pfSense Administrator & Developer Guide

Generated May 2026 from pfsense/pfsense at 9363ac5

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

pfSense is a FreeBSD-based firewall and router operating system maintained by Netgate (Rubicon Communications, LLC). It provides a full PHP-based web management interface (WebGUI) on top of FreeBSD's pf packet filter, with supporting services for DHCP (Kea), DNS (Unbound/dnsmasq), VPN (OpenVPN, strongSwan/IPsec), captive portal, traffic shaping (ALTQ), and package management — all configured through a single XML configuration store (config.xml).

The project traces its lineage to m0n0wall, an embedded firewall created by Manuel Kasper. pfSense extended m0n0wall for full x86 hardware, adding a richer web GUI, plugin architecture, VPN services, and enterprise features like CARP high availability.

Architecture Diagram

┌─────────────────────────────────────────────────────┐
│                     pfSense Host                     │
│                    (FreeBSD OS)                       │
│                                                      │
│  ┌──────────────┐  ┌─────────────┐  ┌────────────┐  │
│  │  WebGUI      │  │  Services   │  │  pf        │  │
│  │  (PHP/nginx) │  │  (DHCP,DNS, │  │  Firewall  │  │
│  │  :443/:80    │  │   NTP,VPN,  │  │  Engine    │  │
│  │              │  │   captive   │  │            │  │
│  │  index.php   │  │   portal)   │  │  pfctl     │  │
│  │  (dashboard) │  │             │  │  (rules,   │  │
│  │              │  │             │  │   NAT,     │  │
│  │  *.php pages │  │             │  │   states)  │  │
│  └──────┬───────┘  └──────┬──────┘  └─────┬──────┘  │
│         │                 │                │         │
│  ┌──────┴─────────────────┴────────────────┴──────┐  │
│  │              config.xml (/cf/conf/)             │  │
│  │         Single XML configuration store          │  │
│  └────────────────────────────────────────────────┘  │
│                                                      │
│  ┌──────────────┐  ┌─────────────┐  ┌────────────┐  │
│  │  RC Scripts   │  │  PHP Shell  │  │  Build     │  │
│  │  (src/etc/)   │  │  Sessions   │  │  System    │  │
│  │  bootup,      │  │  (console   │  │  (build.sh │  │
│  │  backup,      │  │   commands) │  │   tools/)  │  │
│  │  services     │  │             │  │            │  │
│  └──────────────┘  └─────────────┘  └────────────┘  │
└─────────────────────────────────────────────────────┘

Component Inventory

Component Path Role
WebGUI pages src/usr/local/www/*.php Web interface for all configuration and status
Core includes src/etc/inc/*.inc PHP libraries: auth, config, filter, VPN, services, utilities
RC scripts src/etc/rc.* Shell scripts for bootup, shutdown, backup, service control
PHP shell sessions src/etc/phpshellsessions/ Console menu commands (option 12)
Sbin utilities src/usr/local/sbin/ Helper scripts for OpenVPN, PPP, DHCP, ACB
Dashboard widgets src/usr/local/www/widgets/ Modular dashboard components
Captive portal src/usr/local/captiveportal/ Portal authentication endpoint
Form classes src/usr/local/www/classes/Form/ PHP form rendering framework
CSRF protection src/usr/local/www/csrf/ CSRF token management (csrf-magic)
Wizards src/usr/local/www/wizards/ Setup wizard, OpenVPN wizard, traffic shaper wizard
Build system build.sh, tools/ Image building, Poudriere, Rector
Filesystem services src/usr/local/pfSense/include/Services/ Filesystem abstraction with caching
Localization src/usr/local/share/locale/ 40+ language .po/.mo files
Package metadata src/usr/local/pkg/ Package configuration (e.g., miniupnpd)
Config templates tools/templates/ Core package templates, OVF, repo configs
Installer tools tools/installer/ Config recovery script
Rector rules tools/rector/ Automated code refactoring (PHP AST transforms)

Technology Stack

Layer Technology
Operating System FreeBSD (custom build)
Firewall Engine pf (packet filter) via pfctl
Web Server nginx (serving PHP via PHP-FPM)
Application Language PHP (primary), Shell/Bash (scripts)
Configuration Store XML (/cf/conf/config.xml)
DHCP Server Kea (v4/v6), ISC dhcpd (legacy)
DNS Unbound (resolver), dnsmasq (forwarder)
VPN OpenVPN, strongSwan (IPsec), mpd5 (L2TP/PPTP)
Certificates OpenSSL
Authentication Local DB, RADIUS, LDAP, TOTP
High Availability CARP, pfsync, XMLRPC config sync
Traffic Shaping ALTQ (CBQ, PRIQ, HFSC, FAIRQ)
Package Management FreeBSD pkg (custom repos)
Build System Shell scripts, Poudriere, Rector
PHP Dependencies symfony/cache, symfony/console, nette/utils, simplepie, mikehaertl/php-shellcommand

Note

The PHP dependencies are managed via Composer. The vendor directory installs to src/usr/local/pfSense/include/vendor (not the standard vendor/ root), keeping third-party code within the pfSense include path.

Data Flow: Firewall Rule Change

1. Admin edits rule in WebGUI (firewall_rules_edit.php)
2. PHP writes updated rule to config.xml (xmlparse.inc)
3. Filter reload triggered (rc.filter_configure)
4. pf rules regenerated from config.xml (filter.inc)
5. pfctl loads new ruleset atomically
6. States table updated; new connections use new rules

Data Flow: Captive Portal Authentication

1. Client connects to captive portal interface
2. pf redirects HTTP to captive portal daemon
3. Client browser loads captiveportal/index.php
4. User submits credentials (local/RADIUS/voucher)
5. captiveportal_authenticate_user() validates
6. On success: portal_allow() adds pf passthrough rule
7. Client gets internet access for session duration
8. On timeout/logout: pf rule removed, session ended

2. System Requirements

Hardware

Resource Minimum Production Recommended
CPU 64-bit x86 (amd64) Multi-core, AES-NI for VPN acceleration
RAM 1 GB 4-8 GB (more for large state tables, IDS/IPS packages)
Storage 8 GB 32 GB+ SSD (for logging, packages, RRD)
NICs 2 3+ (Intel recommended for driver stability)

RAM Disk Considerations

pfSense can optionally mount /tmp and /var as RAM disks to reduce disk I/O (important for CF/SD media). Default sizes:

Disk Default Size
/tmp 40 MB
/var 60 MB

Configured at System > Advanced > Miscellaneous. The system checks available memory before mounting (ramdisk_check_size()) and falls back to disk if insufficient RAM is available.

Important

When RAM disks are enabled, data in /tmp and /var is volatile. The system automatically backs up RRD, DHCP leases, captive portal databases, logs, alias tables, and package data to the RAM Disk Store (/cf/conf/RAM_Disk_Store/) via periodic RC scripts. The pkg database is symlinked from /root/var/db/pkg to survive reboots.

Supported Platforms

  • Bare metal x86-64 hardware
  • VMware ESXi / Workstation / Fusion
  • Proxmox VE (KVM)
  • Microsoft Hyper-V
  • Oracle VirtualBox
  • QEMU/KVM
  • Netgate appliances (purpose-built hardware)

3. Configuration Reference

Configuration Store

All pfSense settings are stored in a single XML file:

Property Value
Path /cf/conf/config.xml
Format XML
Backup location /cf/conf/backup/ (automatic backups on change)
RAM Disk Store /cf/conf/RAM_Disk_Store/ (periodic backups of volatile data)

Configuration is read and written by the PHP include libraries in src/etc/inc/:

  • config.inc — main config read/write
  • config.lib.inc — config library functions
  • xmlparse.inc / xmlparse_attr.inc — XML parsing
  • config.console.inc — console-based config operations
  • config.gui.inc — GUI-based config operations

The config accessor pattern uses path-based functions:

  • config_get_path("interfaces/wan/ipaddr") — read a config value
  • config_path_enabled("captiveportal/zone", "httpslogin") — check if a flag is set
  • array_get_path() / array_set_path() — array navigation helpers

Environment Variables (VPN Authentication)

These environment variables are read by VPN authentication scripts during client connection:

Variable Read By Purpose
common_name ipsec.attributes.php Certificate CN for IPsec session
username ipsec.auth-user.php, openvpn.auth-user.php Authenticating username
password ipsec.auth-user.php, openvpn.auth-user.php Authenticating password
authcfg ipsec.auth-user.php Comma-separated auth server names
dev openvpn.auth-user.php, openvpn.attributes.php OpenVPN tunnel device name
untrusted_port openvpn.auth-user.php, openvpn.attributes.php Client source port

Important

These variables are set by strongSwan (IPsec) and OpenVPN daemons during the authentication callback. They are not user-configurable — they exist in the execution environment of the auth scripts.

Interface Configuration Types

Configured at Interfaces > (interface name) — stored in config.xml under <interfaces>:

IPv4 Type Config Value Description
Static IP address string Manual IPv4 address
DHCP dhcp Obtain via DHCP
PPPoE pppoe PPP over Ethernet
PPTP pptp Point-to-Point Tunneling
L2TP l2tp Layer 2 Tunneling
PPP ppp Serial/cellular PPP
None (empty) No IPv4 address
IPv6 Type Config Value Description
Static IPv6 address string Manual IPv6 address
SLAAC slaac Stateless Address Autoconfiguration
DHCPv6 dhcp6 Obtain via DHCPv6
6to4 6to4 6to4 tunnel
6rd 6rd IPv6 Rapid Deployment
Track Interface track6 Track another interface's prefix
None (empty) No IPv6 address

Advanced DHCP Client Options

The interface configuration page exposes advanced DHCP client settings (stored under each interface's XML block):

Setting Config Key Purpose
Protocol Timeout adv_dhcp_pt_timeout DHCP protocol timeout
Protocol Retry adv_dhcp_pt_retry Number of retries
Select Timeout adv_dhcp_pt_select_timeout Time to wait for offers
Reboot adv_dhcp_pt_reboot Time before reboot attempt
Backoff Cutoff adv_dhcp_pt_backoff_cutoff Max backoff interval
Initial Interval adv_dhcp_pt_initial_interval First retry interval
Send Options adv_dhcp_send_options Custom DHCP send options
Request Options adv_dhcp_request_options Custom DHCP request options
Required Options adv_dhcp_required_options Options required in DHCP offer
Option Modifiers adv_dhcp_option_modifiers Override specific DHCP options
Config File Override adv_dhcp_config_file_override_path Path to custom dhclient.conf
DHCP VLAN Priority dhcpcvpt VLAN CoS priority for DHCP packets

Wireless Interface Configuration

When an interface is wireless, additional settings are available under the <wireless> XML block:

Setting Config Key Values
Standard wireless/standard 11a, 11b, 11g, 11n, 11ac
Mode wireless/mode bss (client), hostap (AP), adhoc
SSID wireless/ssid Network name
Channel wireless/channel Channel number
Channel Width wireless/channel_width 20, 40, 80 MHz
TX Power wireless/txpower Transmit power level
WPA Mode wireless/wpa/wpa_mode 1 (WPA), 2 (WPA2), 3 (WPA+WPA2)
WPA Key Management wireless/wpa/wpa_key_mgmt WPA-PSK, WPA-EAP
WPA Pairwise wireless/wpa/wpa_pairwise CCMP, TKIP
Hidden SSID wireless/hidessid enabled/disabled
802.1X Auth Server wireless/auth_server_addr RADIUS server IP

Build System Configuration

The build system uses build.conf (sample at build.conf.sample) for local overrides. Key variables set in tools/builder_defaults.sh:

Variable Purpose
PRODUCT_NAME Product name (pfSense)
FREEBSD_BRANCH FreeBSD source branch to build from
DEFAULT_ARCH_LIST Target architectures
RSYNCIP, RSYNCUSER, RSYNCPATH Snapshot upload destinations
PKG_RSYNC_HOSTS Package repo sync hosts
PKG_REPO_SERVER_DEVEL Dev package repo server
PKG_REPO_SERVER_RELEASE Release package repo server

4. Deployment & Scaling

Build System

pfSense images are built using build.sh at the repository root. The build system compiles FreeBSD from source with pfSense patches, creates packages via Poudriere, and produces installer images.

Build Targets

./build.sh [options] <target>
Target Output
iso ISO installer image
memstick USB installer (VGA console)
memstickserial USB installer (serial console)
memstickadi USB installer (ADI/Netgate appliances, amd64 only)
ova VMware OVA appliance (release builds, amd64 only)
all memstick + memstickserial + memstickadi (+ ova for release)
none Package repo only, no images

Build Options

Flag Short Effect
--no-buildworld -c Skip FreeBSD world and kernel build
--no-cleanobjdir -d Preserve FreeBSD object directory
--resume-image-build -r Skip build, jump to image creation
--setup Install builder prerequisites
--update-sources Fetch/update FreeBSD sources
--build-kernels Build all configured kernels
--build-kernel NAME Build specific kernel
--install-extra-kernels NAME Add extra kernel to image
--snapshots Build snapshot images
--poudriere-snapshots Update Poudriere packages
--setup-poudriere Install Poudriere and create jails/ports
--create-unified-patch Create unified FreeBSD patch
--update-poudriere-jails Update Poudriere jails
--update-poudriere-ports Update Poudriere ports tree
--update-pkg-repo Rebuild ports and update pkg repo
--upload -U Upload pkgs/snapshots after build
--skip-final-rsync -i Skip final rsync to distribution server
-V VARNAME Print value of build variable
-a ARCH_LIST Override architecture list

Note

The build process sources tools/builder_defaults.sh for default configuration and tools/builder_common.sh for shared functions. Local overrides go in build.conf (not tracked in version control).

Build Pipeline

1. clean_builder()          — Clean previous build artifacts
2. update_freebsd_sources() — Fetch/update FreeBSD source tree
3. depend_check()           — Verify build dependencies
4. make_world()             — Build FreeBSD world
5. build_all_kernels()      — Compile kernel(s)
6. installkernel()          — Install kernel to staging
7. clone_to_staging_area()  — Prepare staging filesystem
8. install_pkg_install_ports() — Install pfSense packages
9. core_pkg_create_repo()   — Create core package repository
10. create_*_image()        — Generate installer images (per target)
11. snapshots_create_sha256() — Generate checksums
12. snapshots_scp_files()   — Upload (if --upload)

High Availability (CARP)

pfSense supports active/passive failover using CARP:

  1. Virtual IPs — Create CARP VIPs at Firewall > Virtual IPs on both nodes
  2. Config Sync — Configure at System > High Avail. Sync (XMLRPC-based)
  3. State Sync — Uses pfsync to synchronize firewall state tables
  4. DHCP Failover — Automatic pool sharing between primary and backup

Console commands for CARP management (via PHP shell sessions):

  • enablecarp / disablecarp — toggle CARP
  • enablecarpmaint / disablecarpmaint — enter/exit maintenance mode

Package System

pfSense uses FreeBSD's pkg package manager with custom repositories. Package management:

  • Install: WebGUI at System > Package Manager or console installpkg session
  • Remove: WebGUI or console uninstallpkg session
  • Repo config: src/usr/local/etc/pkg/repos/FreeBSD.conf
  • Package signing keys: src/usr/local/share/pfSense/keys/pkg/trusted/

Warning

Do not install packages from the FreeBSD default repositories. pfSense uses its own package repositories with versions tested against the pfSense FreeBSD base. Mixing repos can break the system.


5. Operations

Backup and Recovery

Automated Backups

pfSense includes several RC scripts that periodically back up volatile data to the RAM Disk Store (/cf/conf/RAM_Disk_Store/):

Script Backs Up Archive
rc.backup_rrd.sh RRD graph databases (/var/db/rrd/) rrd.tgz
rc.backup_dhcpleases.sh DHCP leases (dhcpd + Kea at /var/dhcpd/var/db/, /var/lib/kea/) dhcpleases.tgz
rc.backup_captiveportal.sh Captive portal DBs and vouchers (/var/db/captiveportal*.db, voucher*.db) Individual .tgz per DB
rc.backup_logs.sh System logs (/var/log/) logs.tgz
rc.backup_aliastables.sh Alias table data (/var/db/aliastables/) Individual .tgz per table
rc.backup_packages_data.sh Package-specific data directories Individual .tgz per package

These scripts are called automatically by ramdisk_make_backup() during shutdown and periodically during operation.

Tip

The backup scripts use timestamp comparison to avoid re-archiving unchanged data. Only modified files are re-compressed.

AutoConfigBackup (ACB)

pfSense includes an automatic cloud backup service (ACB) at Services > Auto Config Backup:

  • Encrypts and uploads config.xml to Netgate's servers
  • Managed by src/usr/local/sbin/execacb.php and acbupload.php
  • Key management at Services > Auto Config Backup > Settings

Manual Backup/Restore

  • WebGUI: Diagnostics > Backup & Restore — download/upload XML
  • Console: Config recovery available during installation via tools/installer/recover_configxml.sh

Config Recovery from Disk

The installer includes a config recovery tool (tools/installer/recover_configxml.sh) that:

  1. Scans for FreeBSD UFS and ZFS partitions
  2. Presents a dialog for partition selection
  3. Mounts the selected partition (with fsck retry for dirty UFS)
  4. For ZFS: imports the pool (supports both pfSense and legacy zroot pool names)
  5. Copies config.xml and SSH host keys to /tmp/recovered_config/
  6. Cleanly unmounts and exports

Note

ZFS recovery handles both new-style layout (pool name pfSense with /cf as a separate dataset) and old-style layout (pool name zroot).

RAM Disk Management

The RAM disk subsystem (src/etc/rc.ramdisk_functions.sh) provides:

Function Purpose
ramdisk_check_enabled() Reads system/use_mfs_tmpvar from config.xml
ramdisk_is_active() Checks enabled AND not failed
ramdisk_check_size() Verifies available RAM can fit requested sizes
ramdisk_try_mount() Mounts tmpfs for /tmp or /var
ramdisk_make_backup() Triggers all backup scripts
ramdisk_relocate_pkgdb() Moves pkg DB between /var and /root/var
ramdisk_link_pkgdb() Creates symlinks for pkg DB on RAM disks
ramdisk_get_size() Returns configured or default size for tmp/var

Failure handling: If RAM disk mounting fails, a flag file (/conf/ram_disks_failed) is created, preventing further attempts until cleared with ramdisk_reset_status().

Bogon Network Updates

The script src/etc/rc.update_bogons.sh periodically downloads updated bogon (unallocated IP) lists:

  • IPv4: https://files.netgate.com/lists/fullbogons-ipv4.txt
  • IPv6: https://files.netgate.com/lists/fullbogons-ipv6.txt

Process:

  1. Sleep for a random interval (0-86400s) to distribute load
  2. Download bogon files and checksums
  3. Verify MD5 checksums
  4. Check pf table-entries capacity before loading
  5. Strip private ranges (192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 for v4; fc00::/7 for v6)
  6. Atomically replace pf tables (pfctl -t bogons -T replace)

Tip

Custom bogon URLs can be set by creating /var/etc/bogon_custom with v4url, v6url, v4urlcksum, and v6urlcksum variables.

Service Management

Services are controlled via the WebGUI (Status > Services) and the console:

Console Session Purpose
svc General service control
restartdhcpd Restart DHCP server
restartipsec Restart IPsec
restartallwan Restart all WAN interfaces
resetwebgui Reset WebGUI to defaults
enablesshd Enable SSH daemon

Monitoring

Dashboard widgets provide real-time monitoring:

  • System Information (CPU, RAM, disk, uptime)
  • Traffic Graphs (per-interface bandwidth)
  • Gateway Status (latency, packet loss)
  • Thermal Sensors (CPU temperature)
  • S.M.A.R.T. Status (disk health)

Logs at Status > System Logs cover:

  • Firewall (pf filter log)
  • DHCP
  • DNS (Resolver/Forwarder)
  • VPN (OpenVPN, IPsec)
  • System (general, auth, NTP)
  • Packages

6. Performance

Firewall State Table

The pf state table tracks active connections. Key tuning:

  • System > Advanced > Firewall & NAT > Firewall Maximum States — default is auto-calculated based on RAM
  • Table entries limit — affects bogon table capacity; increase for large bogon lists or alias tables
  • Monitor at Diagnostics > States Summary

RAM Disk Sizing

Filesystem Default Increase When
/tmp 40 MB Heavy package use, large temp files
/var 60 MB Extensive logging, large DHCP pools, many RRD graphs

The system checks vm.stats.vm.v_free_count * vm.stats.vm.v_page_size against the total requested RAM disk size before mounting.

Traffic Shaping

ALTQ-based traffic shaping queues are configured at Firewall > Traffic Shaper. Supported schedulers:

Scheduler Use Case
CBQ (Class-Based Queuing) General-purpose hierarchical shaping
PRIQ (Priority Queuing) Simple priority-based scheduling
HFSC (Hierarchical Fair Service Curve) Low-latency guarantees with bandwidth sharing
FAIRQ (Fair Queuing) Per-flow fairness

Note

Traffic shaper wizards at Firewall > Traffic Shaper > Wizards generate ALTQ configurations for common scenarios (VoIP priority, gaming, streaming) based on your WAN bandwidth.


7. Security

Authentication Architecture

pfSense supports multiple authentication backends configured at System > Authentication Servers:

Method Implementation
Local Database Users in config.xml, passwords hashed
RADIUS Standard RADIUS protocol with attribute support
LDAP LDAP/LDAPS bind authentication

Authentication is used by:

  • WebGUI login
  • OpenVPN client authentication (openvpn.auth-user.php)
  • IPsec Xauth/EAP authentication (ipsec.auth-user.php)
  • Captive portal
  • User Manager privilege system

VPN Authentication Flow

OpenVPN (src/etc/inc/openvpn.auth-user.php):

  1. Reads credentials from environment variables or GET parameters
  2. Optionally enforces strictusercn (username must match certificate CN)
  3. Iterates configured auth servers
  4. Calls authenticate_user() against each backend
  5. On success: applies RADIUS attributes (DNS push, route push, framed IP)
  6. Writes client-specific options to {tmp_path}/{username}

IPsec (src/etc/inc/ipsec.auth-user.php):

  1. Reads credentials from environment or GET parameters
  2. Enforces strictusercn if configured
  3. Validates against configured auth servers
  4. For local auth: checks user-ipsec-xauth-dialin privilege
  5. Optionally validates group membership (ipsec/client/auth_groups)
  6. On success: loads ipsec.attributes.php for Cisco ACL rules

Warning

IPsec Xauth users must have the user-ipsec-xauth-dialin privilege assigned in System > User Manager. Without it, local authentication succeeds but access is denied.

OCSP Verification

OpenVPN TLS verification (src/etc/inc/openvpn.tls-verify.php) supports:

  • Certificate depth validation
  • OCSP stapling check against configured OCSP URL
  • Per-server OCSP configuration in config.xml

CSRF Protection

The WebGUI uses csrf-magic (src/usr/local/www/csrf/) for cross-site request forgery protection:

  • csrf-magic.php — PHP-side token generation and validation
  • csrf-magic.js — Client-side token injection into forms

Privilege System

User privileges are defined in src/etc/inc/priv.defs.inc and src/etc/inc/priv/user.priv.inc. Each WebGUI page declares its required privilege in a header block:

##|+PRIV
##|*IDENT=page-system-login-logout
##|*NAME=System: Login / Logout / Dashboard
##|*DESCR=Allow access to the 'System: Login / Logout' page and Dashboard.
##|*MATCH=index.php*
##|-PRIV

Privilege checks are enforced by auth_check.inc on every page load.

Certificate Management

Managed at System > Cert. Manager:

  • CAs — Create and manage Certificate Authorities
  • Certificates — Server, user, and device certificates
  • CRLs — Certificate Revocation Lists
  • Renewal — Automated certificate renewal (system_certmanager_renew.php)

SSL configuration for the WebGUI and services uses an internal CA (src/usr/local/share/pfSense/ssl/openssl.cnf). The Netgate CA certificate is bundled at src/usr/local/share/pfSense/ssl/netgate-ca.pem.

RADIUS Dictionary

A custom RADIUS dictionary (src/usr/local/share/pfSense/radius/dictionary.pfsense) defines pfSense-specific RADIUS attributes for enhanced captive portal and VPN integration.

Caution

The diag_command.php page provides a shell command prompt in the WebGUI. Access should be strictly limited to administrators. An attacker with access to this page has full root-level control of the system.


8. Developer Internals

Repository Structure

pfsense/pfsense/
├── build.sh                    # Main build entry point
├── build.conf.sample           # Build configuration template
├── composer.json               # PHP dependency management
├── rector.php                  # Rector code transform configuration
├── src/
│   ├── etc/
│   │   ├── inc/                # Core PHP include libraries
│   │   │   ├── auth.inc        # Authentication functions
│   │   │   ├── config.inc      # Configuration read/write
│   │   │   ├── filter.inc      # pf rule generation
│   │   │   ├── interfaces.inc  # Network interface management
│   │   │   ├── ipsec.inc       # IPsec functions
│   │   │   ├── openvpn.inc     # OpenVPN functions
│   │   │   ├── services.inc    # Service management
│   │   │   ├── shaper.inc      # Traffic shaping
│   │   │   ├── unbound.inc     # DNS Resolver config
│   │   │   ├── captiveportal.inc # Captive portal logic
│   │   │   ├── vpn.inc         # VPN utilities
│   │   │   ├── util.inc        # General utilities
│   │   │   ├── globals.inc     # Global variable definitions
│   │   │   ├── functions.inc   # Core helper functions
│   │   │   ├── priv.defs.inc   # Privilege definitions
│   │   │   ├── xmlparse.inc    # XML parser
│   │   │   └── ...             # ~60 include files total
│   │   ├── phpshellsessions/   # Console PHP shell commands
│   │   ├── rc.*                # RC shell scripts (boot, backup, services)
│   │   └── skel/               # Default user profile files
│   └── usr/local/
│       ├── www/                # WebGUI PHP pages
│       │   ├── index.php       # Dashboard
│       │   ├── firewall_*.php  # Firewall rules, NAT, aliases
│       │   ├── interfaces*.php # Interface configuration
│       │   ├── services_*.php  # Service configuration
│       │   ├── vpn_*.php       # VPN configuration
│       │   ├── system_*.php    # System settings
│       │   ├── status_*.php    # Status/monitoring pages
│       │   ├── diag_*.php      # Diagnostic tools
│       │   ├── pkg*.php        # Package management
│       │   ├── wizard.php      # Wizard engine
│       │   ├── classes/        # Form rendering framework
│       │   ├── widgets/        # Dashboard widgets
│       │   ├── wizards/        # Wizard definitions (XML + PHP)
│       │   ├── csrf/           # CSRF protection
│       │   ├── css/            # Stylesheets (themes)
│       │   ├── js/             # Client-side JavaScript
│       │   └── includes/       # Shared PHP includes
│       ├── sbin/               # System helper scripts
│       ├── captiveportal/      # Captive portal entry point
│       ├── pfSense/include/    # Namespaced PHP classes + vendor
│       ├── pkg/                # Package configurations
│       ├── etc/pkg/repos/      # Package repository config
│       └── share/              # Locale, keys, SSL, Kea scripts
├── tools/
│   ├── builder_common.sh       # Shared build functions
│   ├── builder_defaults.sh     # Build variable defaults
│   ├── build_snapshots.sh      # Snapshot build automation
│   ├── installer/              # Config recovery script
│   ├── rector/                 # Code refactoring rules
│   ├── conf/                   # Poudriere configuration
│   ├── scripts/                # Utility scripts (privdefs generator, DH params)
│   └── templates/              # Package templates, OVF, repo configs
└── tests/
    └── ConfigLibTest.php       # Configuration library tests

WebGUI Page Architecture

Each WebGUI page follows a consistent pattern:

  1. Privilege declaration — ##|+PRIV ... ##|-PRIV block
  2. Include files — guiconfig.inc, feature-specific .inc files
  3. POST handling — process form submissions, validate, write to config
  4. GET/display — read config, render HTML with PHP
  5. Page output — head.inc (header), page content, foot.inc (footer)

The Form rendering framework (src/usr/local/www/classes/Form/) provides:

  • Form.class.php — Main form container
  • Section.class.php — Form sections
  • Group.class.php — Input groups
  • Input.class.php — Text, number, hidden inputs
  • Select.class.php — Dropdown selects
  • Checkbox.class.php — Checkboxes
  • Button.class.php — Submit/action buttons
  • IpAddress.class.php — IP address input with validation
  • Textarea.class.php — Text areas
  • StaticText.class.php — Read-only display text
  • Modal.class.php — Modal dialogs

Dashboard Widget System

Widgets are self-contained PHP files in src/usr/local/www/widgets/widgets/*.widget.php with supporting files:

Directory Contains
widgets/widgets/ Widget PHP files (render logic)
widgets/include/ Widget include files (title, title_link vars)
widgets/javascript/ Widget-specific JavaScript

The dashboard (index.php) loads widgets dynamically based on the user's saved sequence in config.xml. Widgets support:

  • Multiple instances of the same widget
  • Drag-and-drop reordering via jQuery UI Sortable
  • Collapse/expand state persistence
  • AJAX refresh via register_ajax() for periodic updates
  • Configurable columns (1-4, set at System > General Setup)

Wizard System

Wizards are defined in XML (src/usr/local/www/wizards/*.xml) and processed by wizard.php. The wizard engine supports:

  • Multi-step forms with validation
  • Include files for PHP logic (*.inc alongside XML)
  • Pre-built wizards: Setup (setup_wizard.xml), OpenVPN (openvpn_wizard.xml), Traffic Shaper (traffic_shaper_wizard_*.xml)

Rector Code Transformation

The project uses Rector (PHP AST refactoring tool) for automated code modernization:

Configuration (rector.php):

  • Scans src/ directory
  • Processes .php and .inc files
  • Skips vendor directory and priv.defs.inc

Custom Rule — ArrayGetExprRector (tools/rector/src/Rector/Rules/ArrayGetExprRector.php):

  • Transforms $g['key'] → g_get('key')
  • Transforms $config['path'] → config_get_path('path')
  • Modernizes array access patterns across the codebase
// rector.php configuration
$rectorConfig->ruleWithConfiguration(Rules\ArrayGetExprRector::class,
    ['g' => 'g_get', 'config' => 'config_get_path']);

Test fixtures in tools/rector/tests/Rector/ArrayGetExprRector/ cover:

  • Simple assignment transforms
  • Variable key transforms
  • Multi-level array access
  • Skip conditions (isset checks, LHS assignments)

Filesystem Service Layer

The pfSense\Services\Filesystem namespace (src/usr/local/pfSense/include/Services/Filesystem/) provides an abstraction for filesystem operations with caching:

Class Role
AbstractProvider Base class with Symfony Cache adapter (PhpFilesAdapter, 10s TTL)
SystemProvider Queries filesystem via /bin/df, builds hierarchical filesystem tree
Filesystem Individual filesystem data model
Filesystems Collection/manager for filesystem instances

Dependencies used:

  • symfony/cache — PhpFilesAdapter for filesystem query caching
  • nette/utils — Arrays::get() and Strings utilities
  • mikehaertl/php-shellcommand — Shell command execution

PHP Shell Sessions (Console Commands)

The console menu option 12 provides a PHP shell with pfSense context. Available commands are implemented as PHP scripts in src/etc/phpshellsessions/:

Command Purpose
changepassword Change user password
enablesshd Enable SSH daemon
gatewaystatus Display gateway status
gitsync Sync from git repository
installpkg / uninstallpkg Package management
listpkg List installed packages
enablecarp / disablecarp Toggle CARP
enablecarpmaint / disablecarpmaint CARP maintenance mode
disabledhcpd / restartdhcpd DHCP service control
restartipsec Restart IPsec
restartallwan Restart all WAN interfaces
resetwebgui Reset web configurator
removeshaper Remove traffic shaper configuration
removepkgconfig Remove package configuration
upgradeconfig Run config upgrade routines
cryptconfig Encrypt/decrypt config.xml
disablereferercheck Disable HTTP referer enforcement
enableallowallwan Add pass-all rule to WAN (emergency access)
externalconfiglocator Find config.xml on external media
generateguicert Generate new WebGUI certificate
pfanchordrill / pftabledrill Debug pf anchors/tables
savevoucher Export captive portal vouchers

Client-Side JavaScript

File Purpose
pfSense.js Core WebGUI JavaScript (events, AJAX, form handling)
pfSenseHelpers.js Helper functions for dynamic forms
polyfills.js Browser compatibility polyfills
traffic-graphs.js Real-time traffic graph rendering

CSS Themes

Theme File
pfSense (default) css/pfSense.css
pfSense Dark css/pfSense-dark.css
pfSense BETA css/pfSense-BETA.css
pfSense Dark BETA css/pfSense-dark-BETA.css
Compact RED css/Compact-RED.css
Login page css/login.css

Font: Roboto (bundled as WOFF2 files under css/fonts/).

Testing

Test location: tests/ConfigLibTest.php

The test suite uses PHPUnit (v12.5.8 via Composer dev dependency). Current test coverage focuses on the configuration library functions.

Running tests:

./vendor/bin/phpunit tests/

Note

Test coverage is minimal — only ConfigLibTest.php exists in the repository. The Rector rule tests (tools/rector/tests/) provide additional coverage for the code transformation rules.

Utility Scripts

Script Location Purpose
generate-privdefs.php tools/scripts/ Generate privilege definitions
generate_ffdhe.py tools/scripts/ Generate FFDHE DH parameters
pfSsh.php src/usr/local/sbin/ PHP shell entry point for console
read_xml_tag.sh src/usr/local/sbin/ Read XML config values from shell
read_global_var src/usr/local/sbin/ Read PHP global variables from shell

Localization

Translations use GNU gettext (.po/.mo files) with Zanata for translation management (zanata.xml in repo root). 40+ locales are supported, stored under src/usr/local/share/locale/{locale}/LC_MESSAGES/pfSense.{po,mo}.

Contributing

  • License: Apache License 2.0
  • Code style: Rector enforces consistent array access patterns; .editorconfig defines indentation rules
  • Branching: Development occurs in the pfsense/pfsense repository
  • Build verification: Use build.sh --setup to prepare the build environment, then build and test images

9. Integration Points

RADIUS Integration

pfSense integrates with RADIUS servers for:

  • WebGUI authentication
  • OpenVPN client authentication (with attribute support for DNS push, route push, framed IP)
  • IPsec Xauth authentication (with group membership validation)
  • Captive portal authentication (with per-user bandwidth and session attributes)

RADIUS attributes supported include:

  • nas_identifier — set to openVPN or xauthIPsec
  • nas_port_type — RADIUS_VIRTUAL for VPN
  • dns-servers — pushed to VPN clients
  • routes — pushed as route directives
  • framed_ip / framed_mask — static IP assignment for VPN clients

LDAP Integration

LDAP authentication is configured at System > Authentication Servers and supports:

  • LDAP and LDAPS (SSL/TLS)
  • Custom bind DN and search base
  • Group membership mapping to pfSense groups

XMLRPC Configuration Sync

High-availability setups use XMLRPC (src/usr/local/www/xmlrpc.php) to synchronize configuration between primary and backup nodes. Configurable at System > High Avail. Sync.

Package Hook System

Packages can register custom code execution points:

  • Dashboard hooks: pfSense_handle_custom_code("/usr/local/pkg/dashboard/pre_dashboard")
  • Package-specific XML configuration: src/usr/local/pkg/*.xml
  • Install/deinstall scripts: tools/templates/pkg-install.in, pkg-deinstall.in

Kea DHCP

Kea DHCP server scripts (src/usr/local/share/kea/scripts/kea_run4, kea_run6) provide IPv4 and IPv6 DHCP service as the modern replacement for ISC dhcpd.

DH Parameters

Pre-generated Diffie-Hellman parameters are bundled for VPN and SSL use:

File Key Size
src/etc/dh-parameters.1024 1024-bit
src/etc/dh-parameters.2048 2048-bit
src/etc/dh-parameters.3072 3072-bit
src/etc/dh-parameters.4096 4096-bit
src/etc/dh-parameters.6144 6144-bit
src/etc/dh-parameters.8192 8192-bit

Tip

Use 2048-bit or higher DH parameters for production VPN deployments. The pre-generated parameters avoid the lengthy generation process on low-power hardware.