# 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 execution** — `serial: 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: ```yaml 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`: ```yaml 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) ```bash ansible-playbook upgrade.yml ``` Or with explicit tag: ```bash ansible-playbook upgrade.yml --tags check ``` ### 4. Apply in-branch upgrades ```bash ansible-playbook upgrade.yml -e "perform_upgrade=true" ``` ### 5. Apply upgrade and allow branch crossing (e.g. 2.7 → 2.8) ```bash ansible-playbook upgrade.yml -e "perform_upgrade=true allow_major_upgrade=true" ``` ### 6. Target a single host ```bash 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 ```