pfSenseLab
Redundant cabling across paired rack equipment, evoking active-passive firewall failover
Advanced

pfSense High Availability with CARP: Active-Passive Failover

Build a two-node pfSense HA cluster using CARP virtual IPs, pfsync state synchronization, and XMLRPC config replication — so a dead primary fails over to the secondary with active sessions intact.

By pfSenseLab Editorial · · 8 min read

pfSense high availability rests on three cooperating mechanisms, and understanding which does what is the difference between a working cluster and a confusing one. CARP (Common Address Redundancy Protocol) shares virtual IPs between nodes and elects a master. pfsync replicates the firewall state table so existing connections survive a failover. XMLRPC copies configuration one-way from primary to secondary so the two nodes stay identical. This guide builds a two-node active-passive cluster for a homelab or small office.

Before you start, a hard prerequisite: HA needs spare IP addresses. Each node needs its own real IP on each synced interface (WAN, LAN, and a dedicated sync link), plus a shared CARP VIP that clients actually use as their gateway. So on LAN you’ll consume three addresses (primary, secondary, VIP). On WAN, you need either multiple usable public IPs from your ISP or a setup where the upstream tolerates CARP — many residential ISPs hand out a single IP, which makes true WAN-side CARP impossible without a static block. Confirm your addressing before building anything; this is the most common reason a homelab HA plan stalls.

Topology

Two identical pfSense boxes. A dedicated sync interface (a direct cable between the two units, on its own subnet like 172.16.1.0/30) carries pfsync state and XMLRPC config. Do not run sync traffic over LAN if you can avoid it — a dedicated link keeps state replication off your production segment and is the documented best practice.

RoleLAN real IPWAN real IPSync IP
Primary192.168.1.2(public A)172.16.1.1
Secondary192.168.1.3(public B)172.16.1.2
CARP VIP (LAN)192.168.1.1(public VIP)

Clients use 192.168.1.1 (the VIP) as their gateway — never a node’s real IP.

Step 1: Configure the sync interface on both nodes

On each box, assign the spare NIC as a new interface (e.g., SYNC), set static IPs as in the table, and add a firewall rule on the SYNC interface permitting traffic between the two sync IPs. Without that rule, pfsync and XMLRPC are silently blocked.

Step 2: Create CARP virtual IPs (primary only)

Firewall → Virtual IPs → Add, on the primary:

  • Type: CARP
  • Interface: LAN
  • Address: 192.168.1.1/24 (the VIP)
  • Virtual IP Password: a shared secret (both nodes use the same value — XMLRPC will sync it)
  • VHID Group: a unique number per VIP (e.g., 1)
  • Advertising Frequency: Base 1, Skew 0 on the primary (the secondary gets a higher skew automatically via sync, making it the backup)

Repeat for the WAN VIP if you have the public addressing for it.

Step 3: Configure HA sync / XMLRPC (primary)

System → High Availability Sync:

  • State Synchronization (pfsync): enable, set the sync interface to SYNC, and set the pfsync peer to the secondary’s sync IP.
  • Configuration Synchronization (XMLRPC): set the sync interface, the Synchronize Config to IP to the secondary’s sync IP, and the secondary’s admin username/password.
  • Tick the categories to synchronize (firewall rules, NAT, aliases, VPN, DHCP, etc.).

XMLRPC runs one-way, primary → secondary. You make all config changes on the primary; the secondary receives them automatically. Editing the secondary directly is how clusters drift out of sync — don’t.

Step 4: Set up the secondary

On the secondary, configure only the sync interface and its HA pfsync settings (peer = primary’s sync IP). Do not manually create the CARP VIPs there — XMLRPC pushes them from the primary. Once XMLRPC syncs, the VIPs appear on the secondary in BACKUP state.

Step 5: DHCP and outbound NAT for HA

  • DHCP: on the LAN DHCP scope, set the gateway and DNS offered to clients to the VIP (192.168.1.1), not a node IP. pfSense HA supports DHCP failover; configure the failover peer IP so both nodes can serve leases.
  • Outbound NAT: switch to Manual/Hybrid Outbound NAT and set the translation address to the WAN CARP VIP so outbound traffic uses the shared address and survives failover.

Verify failover

  1. States: Status → CARP — the primary shows VIPs as MASTER, the secondary as BACKUP. If both show MASTER, your sync link is down (split-brain) — fix the SYNC connectivity/firewall rule first.
  2. Sync worked: a rule you add on the primary appears on the secondary within seconds.
  3. Real failover test: from a LAN client, start a continuous ping 8.8.8.8, then reboot or pull the WAN/power on the primary. The secondary should take over the VIPs in roughly a second; ping may drop one or two packets. Active TCP sessions (an SSH session, a download) should survive thanks to pfsync.
  4. Maintenance mode: Status → CARP → Enter Persistent CARP Maintenance Mode on the primary gracefully demotes it so you can patch it — far cleaner than yanking power.

When pfSense HA is the wrong call

HA doubles your hardware, power, and configuration complexity, and it protects against exactly one thing: a node or link failure. It does not protect against a bad config change (XMLRPC will happily replicate your mistake to the secondary), a power outage that takes both nodes, or a misconfiguration that breaks routing on both. For most homelabs, a good config backup plus a cold spare box on the shelf delivers more real resilience per dollar than a live cluster. Build HA when downtime genuinely costs you — a small office gateway, a service with an SLA — and you have the spare public addressing to do WAN-side CARP properly. If you only have a single ISP IP, consider HA on LAN-side services only, or accept that a cold-standby restore is the pragmatic answer.

Comparing platforms? OPNsense also does CARP HA with the same FreeBSD building blocks; see firewallcompare.com for a side-by-side. The pfSense High Availability documentation is the authoritative reference.

Related

Comments