High Availability with OPNsense and CARP: Active/Passive Pair with Zero Downtime

Configure an OPNsense active/passive pair with CARP, pfsync and XMLRPC Config Sync on Proxmox. Automatic failover in under 3 seconds, zero-downtime upgrades, integrated Grafana monitoring — enterprise high availability at zero cost.

High Availability with OPNsense and CARP: Active/Passive Pair with Zero Downtime
CARP high availability architecture OPNsense active passive failover
CARP Architecture: MASTER node handling active traffic and BACKUP node in standby — sharing the same Virtual IP

What is CARP?

CARP (Common Address Redundancy Protocol) is a network protocol that allows multiple machines to share a virtual IP address (VIP). Originally developed for OpenBSD and natively integrated in OPNsense, CARP ensures firewall high availability: if the master node fails, the standby node takes over within seconds, completely transparently to active connections.

In my BOTUM infrastructure, CARP solves three concrete problems:

  • Zero-downtime upgrades: fail over to backup, upgrade master, fail back — no interruption for clients.
  • Failure resilience: Proxmox VM crash, OPNsense crash, network outage — automatic failover in under 3 seconds.
  • Planned maintenance: clean master shutdown, backup takes over, maintenance window with zero SLA impact.

Prerequisites: 2 OPNsense VMs on Proxmox

  • 2 identical OPNsense VMs on Proxmox (same version, same base configuration)
  • 3 network interfaces per VM: WAN, LAN, and SYNC (pfsync)
  • A dedicated switch or VLAN for the synchronization link
  • SSH access to both nodes
  • Same OPNsense version on both nodes (mandatory for config sync)

Recommended Network Architecture

# OPNsense-1 (MASTER)
# - vtnet0 : WAN  → IP: 203.0.113.2/28 (real)
# - vtnet1 : LAN  → IP: 192.168.1.1/24 (real)
# - vtnet2 : SYNC → IP: 192.168.254.1/30

# OPNsense-2 (BACKUP)
# - vtnet0 : WAN  → IP: 203.0.113.3/28 (real)
# - vtnet1 : LAN  → IP: 192.168.1.2/24 (real)
# - vtnet2 : SYNC → IP: 192.168.254.2/30

# Shared CARP VIPs (clients use these IPs)
# - WAN VIP : 203.0.113.4/28  (VHID 1)
# - LAN VIP : 192.168.1.254/24 (VHID 2)
OPNsense web interface CARP VIP configuration VHID skew master backup
OPNsense Interface — CARP VIP configuration with VHID, password and skew (0 = MASTER)

Configure CARP VIPs

Create WAN VIP on MASTER

In OPNsense MASTER: Interfaces > Virtual IPs > Settings > Add

Type         : CARP
Interface    : WAN
IP Address   : 203.0.113.4 / 28
Virtual VHID : 1
VHID Password: MyCarpPassword2026
Advertising frequency - Base : 1
Advertising frequency - Skew : 0   <- 0 = MASTER (high priority)
Description  : WAN-VIP-CARP

Create LAN VIP on MASTER

Type         : CARP
Interface    : LAN
IP Address   : 192.168.1.254 / 24
Virtual VHID : 2
VHID Password: MyCarpPassword2026
Advertising frequency - Base : 1
Advertising frequency - Skew : 0
Description  : LAN-VIP-CARP

Configure BACKUP (Skew 100)

On OPNsense-2 (BACKUP), create the same VIPs with Skew = 100:

# On OPNsense-2 (BACKUP) — same config, only skew changes:
# WAN VIP : VHID 1, Skew 100  <- 100 = BACKUP (low priority)
# LAN VIP : VHID 2, Skew 100

# CARP Priority Rules:
# - Skew 0   = high priority -> MASTER (active)
# - Skew 100 = low priority  -> BACKUP (standby)
# - Lower skew = higher priority node
pfsync state synchronization OPNsense high availability dedicated sync link
pfsync in action: real-time TCP/UDP state sync between MASTER and BACKUP via dedicated SYNC link

pfsync: Connection State Synchronization

pfsync synchronizes the firewall state tables between both nodes in real time. During failover, active TCP connections (SSH, HTTPS, WireGuard VPN tunnels) are not interrupted — the backup already knows all connection states thanks to pfsync.

Enable pfsync on MASTER

System > High Availability > Settings

# System > High Availability > Settings

[High Availability Sync]
+ Synchronize States (pfsync)
Synchronize Interface        : SYNC  (vtnet2)
pfsync Synchronize Peer IP   : 192.168.254.2  <- BACKUP SYNC IP

[Firewall]
+ Synchronize firewall rules
+ Synchronize NAT
+ Synchronize static routes

Enable pfsync on BACKUP

# System > High Availability > Settings (on BACKUP)

[High Availability Sync]
+ Synchronize States (pfsync)
Synchronize Interface        : SYNC  (vtnet2)
pfsync Synchronize Peer IP   : 192.168.254.1  <- MASTER SYNC IP

⚠️ The SYNC link must be isolated on a dedicated VLAN or network. Never route user traffic through this interface.

XMLRPC Config Sync

XMLRPC Config Sync automatically propagates OPNsense configuration from MASTER to BACKUP. Every change on the MASTER (new firewall rule, NAT entry, alias) is synchronized without manual intervention.

# System > High Availability > Settings

[Configuration Synchronization]
Synchronize Config to IP   : 192.168.254.2  <- BACKUP SYNC IP
Remote System Username     : root
Remote System Password     : BackupPassword2026

# Sections to synchronize (check all):
+ Aliases          + Auth Servers     + Certificates
+ DHCP Server      + DNS Resolver     + Firewall Rules
+ Gateways         + Interfaces       + NAT
+ OpenVPN/WireGuard + Routes          + Users and Groups

💡 After each change on the MASTER, click Save & Sync to immediately propagate to the BACKUP.

Testing Failover

Failover testing is mandatory before going to production. It validates that the backup takes over correctly and that connections survive.

Test 1: Graceful Failover

# Verify initial state:
# MASTER: CARP State = MASTER (VIPs active)
# BACKUP: CARP State = BACKUP (VIPs standby)

# Force MASTER to become BACKUP:
# System > High Availability > Forcefully become BACKUP

# BACKUP promotes to MASTER in ~2-3 seconds

Test 2: Hard Failure Simulation

# In Proxmox, power off OPNsense-1 (MASTER) VM:
# qm stop 100

# From a network client:
ping 203.0.113.4
# -> 1-2 packet losses maximum during failover
# -> Backup takes over in 1-3 seconds

# Verify on BACKUP:
# VIP WAN: MASTER | VIP LAN: MASTER  OK

Test 3: Active Connections Survive Failover

# Open an SSH session via the LAN VIP:
ssh admin@192.168.1.254

# Force failover while session is active
# SSH session MUST SURVIVE thanks to pfsync
# If SSH survives -> pfsync works correctly OK
CARP OPNsense failover test timeline traffic switchover master backup
CARP failover timeline: T=0 MASTER active, T=5s failure detected, T=7s BACKUP takes over all VIPs

Production Use Cases: Zero-Downtime Operations

The primary value of CARP in my BOTUM infrastructure is the ability to perform maintenance without any downtime window.

Zero-Downtime OPNsense Upgrade Procedure

# Step 1: Verify BACKUP is healthy
# System > High Availability > Status
# BACKUP: CARP BACKUP, pfsync OK, config synced

# Step 2: Fail over traffic to BACKUP
# On MASTER: System > HA > Forcefully become BACKUP
# BACKUP becomes MASTER, takes all VIPs

# Step 3: Upgrade former MASTER (now BACKUP)
# System > Firmware > Updates > Upgrade
# -> Normal reboot, no traffic impact

# Step 4: Verify MASTER return
# -> Returns to BACKUP mode automatically
# -> Verify: state sync OK + config sync OK

# Step 5: Repeat for second node
# Result: Both nodes upgraded, 0 seconds downtime
Grafana dashboard CARP OPNsense high availability monitoring real-time
Grafana CARP Dashboard — VIP states, failover history, pfsync metrics in real time

CARP Monitoring with Grafana

Building on Post 9 (Grafana + InfluxDB Monitoring), here is how to add CARP tracking to your existing dashboards.

Collect CARP Metrics via Telegraf

# In telegraf.conf — add CARP input:
[[inputs.http]]
  urls = ["http://192.168.1.254/api/diagnostics/interface/getVipStatus"]
  method = "GET"
  username = "telegraf_user"
  password = "YOUR-OPNSENSE-API-TOKEN"
  data_format = "json"
  name_suffix = "_carp"

# Grafana Flux query — CARP state:
from(bucket: "opnsense")
  |> range(start: -1h)
  |> filter(fn: (r) => r._measurement == "http_carp")
  |> filter(fn: (r) => r._field == "status" or r._field == "vhid")

Recommended Dashboard Panels

  • Current CARP state (MASTER/BACKUP) for each VIP — Gauge with alert if INACTIVE
  • Failover event history — Timeline/Log panel (each CARP state change)
  • pfsync counter: states synchronized/second — Time series
  • SYNC link latency — Gauge (alert if > 10ms)
  • Total synchronized firewall states — Stat panel

Conclusion and Next Steps

You now have an active/passive high-availability OPNsense infrastructure with:

  • ✅ CARP VIPs shared between MASTER and BACKUP
  • ✅ pfsync for TCP/UDP connection continuity
  • ✅ XMLRPC Config Sync for automatic configuration propagation
  • ✅ Validated failover tests (graceful + hard failure)
  • ✅ Integrated Grafana monitoring for real-time visibility

This stack gives you an enterprise-grade firewall with RTO < 3 seconds and RPO of 0 — no connections lost, no configurations out of sync.

🔗 Next post: SIEM Wazuh with OPNsense — Security Log Centralization and Real-Time Intrusion Detection.

🔗 Series Hub: OPNsense Enterprise Security Stack on Proxmox

📥 Guide PDF complet

Téléchargez ce guide en PDF pour le consulter hors ligne.

⬇ Télécharger le guide (PDF)

🚀 Aller plus loin avec BOTUM

Ce guide couvre les bases. En production, chaque environnement a ses spécificités. Les équipes BOTUM accompagnent les organisations dans le déploiement, la configuration avancée et la sécurisation de leur infrastructure. Si vous avez un projet, parlons-en.

Discuter de votre projet →
OPNsense Series 📋 Complete series →