pfSense API and Management Automation

A REST API transforms pfSense from a standalone firewall into a programmable infrastructure component. Instead of manual configuration through the web interface, administrators can perform operations via HTTP requests, integrate pfSense into orchestration systems, and adopt an Infrastructure as Code approach. This becomes essential in environments with dozens of devices where manual configuration of each firewall is impractical.

pfSense REST API Package

pfSense does not include a built-in REST API. Programmatic access is provided by the community package pfSense-api , which adds over 200 endpoints for system management.

Installation

The package is installed from the pfSense command line:

pkg-static add https://github.com/jaredhendrickson13/pfsense-api/releases/latest/download/pfSense-2.7.2-pkg-RESTAPI.pkg

After installation, API settings are available under System > REST API in the web interface.

Authentication

The API supports three authentication methods:

MethodHeaderExpirationRecommendation
Basic AuthAuthorization: Basic <base64>PermanentTesting only
API KeyX-API-Key: <key>PermanentScripts and automation
JWTAuthorization: Bearer <token>Time-limitedInteractive applications

Obtaining a JWT Token

curl -X POST -H "Content-Type: application/json" \
  -u admin:pfsense \
  https://pfsense.example.com/api/v2/auth/jwt

The response contains a token that is then passed in the header:

curl -H "Authorization: Bearer <token>" \
  https://pfsense.example.com/api/v2/firewall/rules

API Key Authentication

API keys are created in the web interface (System > REST API > Settings) and are bound to a user account. Key privileges are inherited from the associated account.

curl -H "X-API-Key: <your-api-key>" \
  https://pfsense.example.com/api/v2/system/info

API Endpoints Overview

System Information

# Get system information
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/system/info

# Version and update status
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/system/version

Firewall Rules

# List all firewall rules
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/firewall/rules

# Create a new rule
curl -X POST -H "Content-Type: application/json" \
  -H "X-API-Key: <key>" \
  -d '{
    "type": "pass",
    "interface": "wan",
    "ipprotocol": "inet",
    "protocol": "tcp",
    "source": "any",
    "destination": "any",
    "dstport": "443",
    "descr": "Allow HTTPS inbound"
  }' \
  https://pfsense.example.com/api/v2/firewall/rules

# Apply changes (required after modifying rules)
curl -X POST -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/firewall/apply

Interface Management

# List network interfaces
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/interface

# Update interface configuration
curl -X PUT -H "Content-Type: application/json" \
  -H "X-API-Key: <key>" \
  -d '{"if": "em1", "descr": "DMZ", "enable": true}' \
  https://pfsense.example.com/api/v2/interface

VPN Management

# List OpenVPN servers
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/vpn/openvpn/server

# List IPsec tunnels
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/vpn/ipsec/phase1

Automation with Ansible

The pfsensible.core collection provides modules for declarative pfSense management through Ansible. The collection communicates with pfSense via xmlrpc and the PHP interface, requiring no additional package installations.

Installing the Collection

ansible-galaxy collection install pfsensible.core

Example Playbook

- name: Configure pfSense firewall
  hosts: pfsense_firewalls
  gather_facts: false
  collections:
    - pfsensible.core

  tasks:
    - name: Create alias for web servers
      pfsense_alias:
        name: web_servers
        type: host
        address: "10.0.1.10 10.0.1.11 10.0.1.12"
        descr: "Production web servers"
        state: present

    - name: Allow HTTPS to web servers
      pfsense_rule:
        name: "Allow HTTPS to web servers"
        interface: WAN
        action: pass
        protocol: tcp
        source: any
        destination: web_servers
        destination_port: 443
        state: present

    - name: Configure DNS resolver
      pfsense_dns_resolver:
        enable: true
        dnssec: true
        forwarding: true

Inventory Configuration

[pfsense_firewalls]
fw01 ansible_host=192.168.1.1

[pfsense_firewalls:vars]
ansible_connection=httpapi
ansible_httpapi_use_ssl=true
ansible_httpapi_validate_certs=false
ansible_user=admin
ansible_password=pfsense
ansible_network_os=pfsensible.core.pfsense

Automation with Terraform

An unofficial Terraform provider for pfSense enables configuration management through declarative HCL files.

terraform {
  required_providers {
    pfsense = {
      source  = "sjafferern/pfsense"
      version = "~> 0.1"
    }
  }
}

provider "pfsense" {
  url      = "https://192.168.1.1"
  user     = "admin"
  password = var.pfsense_password
  insecure = true
}

resource "pfsense_firewall_alias" "blocked_countries" {
  name        = "blocked_countries"
  type        = "network"
  description = "Blocked country subnets"
  entries     = ["10.99.0.0/16", "10.98.0.0/16"]
}

The provider is in early development. Thorough testing is recommended before using it in production environments.

PHP Shell for Programmatic Access

pfSense includes a developer PHP shell accessible via the console (option 12) or SSH. The shell allows direct reading and modification of system configuration.

Accessing the PHP Shell

Enter an option: 12

Starting the pfSense developer shell....
pfSense shell:

Common Operations

// Read current configuration
parse_config(true);
print_r($config['interfaces']);
exec

// Modify configuration
$config['system']['hostname'] = "fw-prod-01";
write_config("Updated hostname via PHP shell");
exec

Playback Scripts

Predefined scripts for common tasks are executed from the command line:

# From SSH or console shell
pfSsh.php playback enablesshd
pfSsh.php playback changepassword
pfSsh.php playback installpkg "Some Package"
pfSsh.php playback listpkg

xmlrpc for Configuration Management

pfSense uses xmlrpc for configuration synchronization between nodes in a high-availability (CARP) cluster. The same mechanism can be used for programmatic reading and writing of configuration data.

xmlrpc is accessible at https://<pfsense-ip>/xmlrpc.php and accepts standard XML-RPC calls with Basic authentication.

The pfsensible.core collection uses xmlrpc as its primary transport for communicating with pfSense.

Backup via API

The REST API enables automated configuration backup creation:

# Download configuration via API
curl -H "X-API-Key: <key>" \
  https://pfsense.example.com/api/v2/system/config \
  -o config-backup-$(date +%Y%m%d).xml

Automated Backup Script

#!/bin/sh
# Daily pfSense configuration backup via API
PFSENSE_HOST="https://192.168.1.1"
API_KEY="your-api-key"
BACKUP_DIR="/backups/pfsense"
DATE=$(date +%Y%m%d-%H%M)

curl -sk -H "X-API-Key: ${API_KEY}" \
  "${PFSENSE_HOST}/api/v2/system/config" \
  -o "${BACKUP_DIR}/config-${DATE}.xml"

# Remove backups older than 30 days
find "${BACKUP_DIR}" -name "config-*.xml" -mtime +30 -delete

Use Cases

Mass Deployment

When deploying multiple pfSense devices, an Ansible playbook applies a unified configuration to all nodes. A typical workflow:

  1. Base pfSense installation on each device
  2. SSH access and credential configuration
  3. Apply playbook with common firewall rules, VPN configuration, and DNS settings
  4. Apply device-specific variables (IP addresses, hostnames)

CI/CD for Firewall Rules

Firewall rules are stored in a Git repository as YAML files. When merged into the main branch, the CI pipeline applies changes via the API or Ansible:

# .gitlab-ci.yml
deploy_firewall_rules:
  stage: deploy
  script:
    - ansible-playbook -i inventory/production firewall-rules.yml
  only:
    - main
  when: manual

Automated Testing

After applying changes, automated checks verify configuration correctness:

# Verify accessibility after rule changes
curl -sf -o /dev/null https://pfsense.example.com/api/v2/system/info \
  -H "X-API-Key: <key>" && echo "API accessible" || echo "API unreachable"

Troubleshooting

IssueCauseSolution
401 UnauthorizedInvalid credentials or expired JWTVerify API key or request a new token
403 ForbiddenInsufficient user privileges for APIAssign required privileges in System > User Manager
Connection refused on API portREST API package not installed or not runningVerify package installation and service status
Changes not applied/api/v2/firewall/apply not calledExecute apply after modifying rules
xmlrpc timeoutLarge config.xml or network issuesIncrease timeout, verify network connectivity
Ansible module cannot find pfSenseIncorrect ansible_network_osSet to pfsensible.core.pfsense

Related Sections

Last updated on