Files
ansible-msp-automations/roles/pfsense_upgrade
2026-04-27 16:26:12 -07:00
..
2026-04-27 13:15:56 -07:00
2026-04-27 16:26:12 -07:00
2026-04-27 13:15:56 -07:00
2026-04-27 13:15:56 -07:00
2026-04-27 13:15:56 -07:00

pfSense Ansible Upgrade Playbook

Upgrades pfSense CE (and pfSense Plus) systems safely via Ansible.

Features

  • Version detection — reads /etc/version, parses branch, patch level, and release type
  • In-branch update check — runs pfSense-upgrade -c to detect available patch releases within your running branch (e.g. 2.7.2 → 2.7.3)
  • New stable branch detection — queries upstream GitHub for the latest stable version and warns if a newer branch (e.g. 2.8.x) has been released
  • Safety gates — upgrade is a no-op unless perform_upgrade=true is explicitly passed
  • Branch-crossing protection — requires allow_major_upgrade=true to upgrade across major/minor branches
  • Pre-upgrade config backup — triggers pfSense's own PHP backup function before touching anything
  • Serial executionserial: 1 ensures HA pairs are never upgraded simultaneously
  • Post-upgrade verification — confirms version changed, services are listening, and the system is up-to-date

Requirements

  • Ansible ≥ 2.12
  • SSH enabled on pfSense (System → Advanced → Admin Access → Enable Secure Shell)
  • Admin user with shell access
  • The raw module is used throughout — Python is not required on pfSense

Quick Start

1. Configure inventory

Edit inventory/hosts.yml with your pfSense host IPs and SSH user:

fw-site-a:
  ansible_host: 192.168.1.1
  ansible_user: admin

2. Configure SSH auth

Either set a private key in inventory/group_vars/pfsense.yml:

ansible_ssh_private_key_file: ~/.ssh/pfsense_rsa

Or use password auth (add ansible_password: yourpassword per host in host_vars/).

3. Check for available upgrades (safe, no changes made)

ansible-playbook upgrade.yml

Or with explicit tag:

ansible-playbook upgrade.yml --tags check

4. Apply in-branch upgrades

ansible-playbook upgrade.yml -e "perform_upgrade=true"

5. Apply upgrade and allow branch crossing (e.g. 2.7 → 2.8)

ansible-playbook upgrade.yml -e "perform_upgrade=true allow_major_upgrade=true"

6. Target a single host

ansible-playbook upgrade.yml -l fw-site-a -e "perform_upgrade=true"

Variables Reference

Variable Default Description
perform_upgrade false Safety gate — must be true to apply upgrades
allow_major_upgrade false Permit upgrades across branch boundaries
auto_reboot true Reboot automatically after upgrade
reboot_timeout 300 Seconds to wait for host after reboot
upgrade_check_timeout 120 Timeout for pfSense-upgrade check
pkg_repo_update true Run pkg update -f before checking
skip_backup_check false Skip pre-upgrade config backup step
notify_webhook_url "" Optional Slack/Teams webhook for results
pfsense_release_url GitHub raw URL Where to fetch upstream latest version

How Update Detection Works

In-branch updates

pfSense-upgrade -d -c is run on the host. It checks the configured pfSense pkg repository (same branch as running system) and returns non-zero if a newer package set is available. The playbook parses the exit code and output to determine availability.

New stable branch detection

The playbook fetches the version file from the pfSense CE GitHub repository (master branch) using FreeBSD fetch. The major.minor of the upstream version is compared to the running system's branch. If they differ and upstream is newer, a warning is displayed regardless of perform_upgrade.

Note: The GitHub master branch reflects the latest stable CE release. Adjust pfsense_release_url if you track a specific branch or use an internal mirror.


HA / CARP Considerations

  • serial: 1 in the playbook ensures only one host upgrades at a time
  • For CARP HA pairs, upgrade the secondary first so the primary continues to pass traffic
  • Group your HA pairs in the inventory and order hosts accordingly
  • Consider adding a task to demote the primary before upgrading if you need zero-downtime

File Structure

pfsense-upgrade/
├── ansible.cfg
├── upgrade.yml                        # Main playbook entry point
├── inventory/
│   ├── hosts.yml                      # Your pfSense hosts
│   └── group_vars/
│       └── pfsense.yml                # Shared SSH + default vars
└── roles/
    └── pfsense_upgrade/
        ├── defaults/
│       └── main.yml               # All default variable values
        └── tasks/
            ├── main.yml           # Task orchestration
            ├── preflight.yml      # SSH check, disk space, binary check
            ├── version_detect.yml # Read and parse current version
            ├── update_check.yml   # pfSense-upgrade check + upstream compare
            ├── upgrade.yml        # Backup + execute upgrade
            └── verify.yml         # Post-reboot version + service check