Manual · pfSentinel v0.2.1

pfSentinel command manual

pfSentinel is a free, open-source command-line tool that backs up pfSense firewalls over SSH or HTTPS. The command is pfs. It runs on Windows and Linux, keeps passwords in the OS keyring, saves a config backup only when something changed, and schedules itself with Windows Task Scheduler, systemd timers or cron.

Show commands for: pfs commands are the same on both; paths, shells and scheduling differ.

Ask an AI assistant instead

Copies a ready prompt plus this whole manual as plain text. Paste it into Claude, ChatGPT or any assistant and ask your question.

Install

Requirements: Python 3.13+ for pip or pipx installs (the standalone binaries need no Python), Windows 10/11 or Linux (tested on Ubuntu), and a pfSense firewall reachable over SSH (recommended) or HTTPS. Tested on pfSense CE 2.8.1. Enable SSH on pfSense under System > Advanced > Admin Access > Secure Shell. Extended targets (RRD, packages, DHCP, aliases, certificates, logs, ZFS, archives) need SSH.

pip

Linux (bash)

python3 -m pip install --user pfsentinel
pfs --version

Windows (PowerShell)

py -m pip install pfsentinel
pfs --version

Linux: On Ubuntu 23.04+ and Debian 12+ the system Python refuses pip install ("externally-managed-environment"). Use pipx below instead.Windows: If pfs is not found afterwards, pip printed a Scripts folder that is not on your PATH; pipx avoids this.

pipx

Installs pfSentinel into its own isolated environment and puts pfs on your PATH. Recommended on both systems.

Linux (bash)

sudo apt install pipx        # Debian/Ubuntu; other distros: your package manager
pipx ensurepath              # then open a new terminal
pipx install pfsentinel
pfs --version

Windows (PowerShell)

py -m pip install --user pipx
py -m pipx ensurepath        # then open a new terminal
pipx install pfsentinel
pfs --version

Standalone binary

No Python needed. Download pfs (Linux) or pfs.exe (Windows) and checksums-sha256.txt from GitHub Releases, then verify and install it in a folder you own, so pfs update install can replace it later without admin rights.

Linux (bash)

cd ~/Downloads
sha256sum -c checksums-sha256.txt --ignore-missing   # must print: pfs: OK
mkdir -p ~/.local/bin
install -m 755 pfs ~/.local/bin/pfs
pfs --version                                        # if not found: open a new terminal

Windows (PowerShell)

cd $env:USERPROFILE\Downloads
(Get-FileHash .\pfs.exe -Algorithm SHA256).Hash.ToLower()
Select-String 'pfs.exe' .\checksums-sha256.txt       # both hashes must match
$dir = "$env:LOCALAPPDATA\pfSentinel"
New-Item -ItemType Directory -Force $dir | Out-Null
Move-Item .\pfs.exe "$dir\pfs.exe" -Force
[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path','User') + ";$dir", 'User')
# open a new PowerShell window, then:
pfs --version

The binary is not code-signed yet, so SmartScreen may warn on first run: choose More info > Run anyway after checking the hash.

From source

Linux (bash)

git clone https://github.com/NX1X/pfSentinel.git
cd pfSentinel
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
pfs --version

Windows (PowerShell)

git clone https://github.com/NX1X/pfSentinel.git
cd pfSentinel
py -m venv .venv
.venv\Scripts\Activate.ps1     # if blocked: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
pip install -e .
pfs --version

Quick start

pfs setup                          # guided first-time wizard (config + first device)
pfs device trust-key home-fw       # pin the SSH host key, if you skipped it in the wizard
pfs device test -d home-fw         # check the connection
pfs backup run -d home-fw          # first backup
pfs schedule enable                # daily 02:00 + weekly Sunday 03:00 (Windows: Administrator PowerShell)

Or step by step: pfs config init, pfs device add, pfs device trust-key <id>, pfs device test, pfs backup run.

Files and locations

WhatWhere
Config fileLinux: ~/.pfsentinel/config.jsonWindows: %USERPROFILE%\.pfsentinel\config.json (print with pfs config path)
Pinned SSH host keysLinux: ~/.pfsentinel/known_hostsWindows: %USERPROFILE%\.pfsentinel\known_hosts
Backups (default)~/Documents/pfSentinel/<device-id>/ (Windows: %USERPROFILE%\Documents\pfSentinel\<device-id>\) (change with pfs config set backup-dir PATH)
Passwords and tokensLinux: GNOME Keyring or KWallet; on servers, WSL and containers the encrypted store ~/.pfsentinel/storeWindows: Windows Credential Manager (Control Panel > Credential Manager > Windows Credentials, entries named pfsentinel)
Scheduled jobsLinux: systemd user timers pfsentinel-daily.timer / pfsentinel-weekly.timer, or tagged crontab lines where there is no systemdWindows: Task Scheduler folder \pfSentinel\ (DailyBackup, WeeklyBackup)
Scheduled run logLinux: journalctl --user -u pfsentinel-backup.service; cron mode: ~/.pfsentinel/logs/scheduled.logWindows: pfs schedule status (last run and result), or Task Scheduler > pfSentinel > History

Credentials. Passwords, SSH key passphrases, Telegram tokens and Slack webhooks are kept in the OS keyring (Windows Credential Manager on Windows; GNOME Keyring or KWallet on a Linux desktop). Where no keyring exists (headless Linux, WSL, containers) pfSentinel uses its own AES-256-GCM encrypted file store, which works unattended. Nothing secret is written to config.json.

Filenames. Backups are named like home-fw_2026-04-30_143022_#001_interfaces+system.xml.gz: device ID, date, time, daily sequence number, changed config sections, extension.

Change detection. Each config backup is compared with the previous one section by section (interfaces, firewall, system, users, packages, dhcp, vpn, routes, minor, initial). A config backup is saved only when something changed, or when it is the first backup for the device.

Retention. Applied after each backup, per type (backup_policy.max_backups_per_type) and globally (backup_policy.keep_days, default 30) in config.json.

Command reference

Usage pattern: pfs [OPTIONS] COMMAND [ARGS].... Every command accepts --help. Running pfs with no arguments prints help.

Global options

OptionDescription
--version, -vShow version
--install-completionInstall shell completion for the current shell
--show-completionPrint the completion script
--helpShow help and exit

Top-level commands

pfs setup
Guided first-time setup: create config and add your first device.
pfs status
Overview of devices, backups and configuration.
pfs list [--device/-d ID]
List available backups (shortcut for pfs backup list).
pfs docs [--no-browser]
Open this manual in your browser and print its URL plus the URL of the plain-text version. --no-browser only prints the links.

pfs backup

pfs backup run

Run a backup for one or all devices. Without --include, --all-extras or --config-only it shows an interactive menu of extra targets when run from a terminal. With --non-interactive (or with no terminal, as in scheduled runs) it never prompts and uses the backup policy from config.

OptionDescription
--device, -d IDDevice ID (default: all enabled devices)
--desc TEXTDescription label
--backup-dir, -o PATHOverride backup directory (default: ~/Documents/pfSentinel, the same on both systems)
--no-notifySuppress notifications
--area NAMEBack up only one config section (HTTPS only). Valid: aliases, captiveportal, cert, dhcpd, filter, interfaces, ipsec, nat, openvpn, routes, services, shaper, syslog, system, users, wol
--no-packagesExclude package config (HTTPS only)
--include LISTExtra targets, repeatable or comma-separated: rrd, pkg, dhcp, aliases, certs, logs
--all-extrasInclude all extra targets
--config-onlyOnly the XML config, skip extras
--non-interactiveNever prompt; use the backup policy from config (scheduled runs use this)
pfs backup run --all-extras
pfs backup run -d home-fw --include rrd,pkg,certs
pfs backup run -d home-fw --config-only --desc "before upgrade"
pfs backup list [--device/-d ID] [--json]
List backups.
pfs backup verify FILENAME
Re-check the SHA-256 checksum and structure (XML for config, tar integrity for archives).
pfs backup delete FILENAME [--yes/-y]
Delete a backup file.
pfs backup restore FILENAME [--target/-t PATH]
Extract a backup to a local path (default .). This does not push anything to pfSense; see Restore to pfSense.
pfs backup diff FILE_A FILE_B
Unified diff between two config backups.
pfs backup info FILENAME
Metadata: timestamp, checksum, size, change categories, verification status.
OptionDescription
--name, -n TEXTFilename substring
--device, -d IDFilter by device
--date YYYY-MM-DDFilter by date
--changes TEXTFilter by change label substring (for example firewall)
--min-size KB, --max-size KBSize range in KB
--jsonOutput as JSON
pfs backup watch [--device/-d ID] [--interval/-i SECONDS] [--desc TEXT]
Poll the device (default every 300 seconds) and back up whenever the config checksum changes. Ctrl+C to stop.
pfs backup snapshot --device/-d ID [--full]
ZFS snapshot backup (pfSense 2.5+ on ZFS). Incremental by default; --full forces a full stream.
pfs backup snapshot-list --device/-d ID
List ZFS snapshots on the device.
pfs backup archive --device/-d ID [--dirs LIST]
Filesystem tar.gz archive (non-ZFS fallback). --dirs takes comma-separated remote directories. Default set: /cf/conf, /usr/local/etc, /var/db/rrd, /boot/loader.conf, /boot/loader.conf.local.

pfs device

pfs device add

Add a device interactively. Every prompt can be pre-filled with options. For SSH devices the wizard also asks for an optional SSH private key path (with a key, the password becomes optional), then shows the device's SSH host key fingerprint and asks you to trust it, and finally offers to test the connection.

OptionDescription
--id TEXTDevice ID slug (for example home-fw)
--label TEXTDisplay name
--host TEXTIP address or hostname
--method TEXTssh, https or http
--username, -u TEXTpfSense username
--ssh-port INTDefault 22
--https-port INTDefault 443
--http-port INTDefault 80
--no-verify-sslSkip TLS certificate check (self-signed pfSense certificate)

pfs device trust-key DEVICE_ID [--yes/-y]

Connect to the device, show its SSH host key SHA256 fingerprint, ask you to confirm, and save it to the pinned host keys file (Linux: ~/.pfsentinel/known_hostsWindows: %USERPROFILE%\.pfsentinel\known_hosts). --yes skips the prompt (verify the fingerprint yourself).

New in 0.2.0: new devices use strict host key checking. An SSH device must be trusted once before backups work, and a later key change is refused as a possible man-in-the-middle until you run trust-key again (for example after reinstalling pfSense).

pfs device list
List configured devices.
pfs device test [--device/-d ID]
Test connectivity to one or all devices.
pfs device edit DEVICE_ID
Change label, host, username, method, password, SSL verification or SSH key.
pfs device remove DEVICE_ID [--yes/-y]
Remove a device from config. Backup files are kept.

pfs config

pfs config show
Show configuration (passwords hidden).
pfs config init [--force]
Create a default config file. --force overwrites an existing one.
pfs config validate
Validate the config and check that credentials are available.
pfs config set KEY VALUE
Change a setting. Supported key: backup-dir. Other settings (extras, ZFS, archive, retention) are edited in config.json.
pfs config path
Print the config file path.

pfs schedule

pfs schedule enable

Enable scheduled backups with the OS scheduler. Scheduled jobs run pfs backup run --non-interactive, which never prompts and uses the backup policy from config.json. The same options work on both systems.

OptionDescription
--daily-time HH:MMDaily backup time (default 02:00)
--weekly-day DAYWeekly backup day (default sunday)
--weekly-time HH:MMWeekly backup time (default 03:00)
--no-weeklyDisable the weekly backup
--task-scheduler / --no-task-schedulerUse the OS scheduler (default). --no-task-scheduler runs in-process and stops when the command exits
pfs schedule disable
Remove the schedule (timers, cron lines or tasks).
pfs schedule status
Show timer or task state, next run and last result. Warns when the config says enabled but nothing is installed.
pfs schedule run-now
Back up all devices immediately (same as pfs backup run).

pfs notify

pfs notify test
Send a test notification to all enabled channels.
pfs notify status
Show all channel statuses.
pfs notify telegram setup | enable | disable | status
Telegram bot notifications. Setup: in Telegram open @BotFather, send /newbot, copy the token, send any message to your new bot, then run pfs notify telegram setup and paste the token; the chat ID is auto-detected. disable keeps credentials.
pfs notify slack setup | enable | disable | status
Slack incoming webhook notifications. Setup: create an app at api.slack.com/apps, activate Incoming Webhooks, add one to a channel, copy the URL (starts with https://hooks.slack.com/services/), then run pfs notify slack setup. disable keeps the webhook URL.

Linux: Desktop notifications on Linux are planned (see the roadmap); use Telegram or Slack meanwhile.Windows: Windows toast notifications need no setup; they show for backups run while you are signed in.

pfs update

pfs update check
Check GitHub Releases for a newer version.
pfs update install [--yes/-y]
Download and install the latest version. Detects how pfSentinel was installed: binary (replaces the file, so it must sit in a folder you can write to), pipx (pipx upgrade pfsentinel) or pip (pip install --upgrade pfsentinel). Verifies the download against the release checksums first.
pfs update revert [--yes/-y]
Roll back to the previous version after a failed update.

Recipes

Copy-paste sequences for common jobs. Replace home-fw and 192.168.1.1 with your device ID and address.

First setup of a device (SSH)

pfs device add --id home-fw --label "Home Firewall" --host 192.168.1.1 --method ssh -u admin
pfs device trust-key home-fw
pfs device test -d home-fw
pfs backup run -d home-fw --config-only
pfs list -d home-fw

SSH key authentication

1. Create a key and print the public half:

Linux (bash)

ssh-keygen -t ed25519 -C "pfsentinel" -f ~/.ssh/pfsentinel_ed25519
cat ~/.ssh/pfsentinel_ed25519.pub

Windows (PowerShell, built-in OpenSSH client)

ssh-keygen -t ed25519 -C "pfsentinel" -f $env:USERPROFILE\.ssh\pfsentinel_ed25519
Get-Content $env:USERPROFILE\.ssh\pfsentinel_ed25519.pub

2. In the pfSense web UI open System > User Manager > (your user) > Authorized SSH Keys, paste the .pub line and save. (pfSense rebuilds authorized_keys from its config, so this is the method that survives reboots.)

3. Point the device at the private key and test:

Linux (bash)

pfs device edit home-fw        # SSH private key path: ~/.ssh/pfsentinel_ed25519
pfs device test -d home-fw

Windows (PowerShell)

pfs device edit home-fw        # SSH private key path: C:\Users\YOU\.ssh\pfsentinel_ed25519
pfs device test -d home-fw

For a new device, give the same path at the "SSH private key path (optional)" prompt of pfs device add. A key passphrase, if you set one, is stored in the OS keyring. For unattended schedules on Linux servers a key without a passphrase avoids the desktop-keyring problem.

To check the fingerprint shown by pfs device trust-key, open a shell on pfSense (console menu option 8, or SSH) and run:

for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done

Nightly scheduled backups

Linux (systemd user timers; runs while logged out once lingering is on)

pfs schedule enable --daily-time 01:30 --no-weekly
loginctl enable-linger $USER
pfs schedule status
systemctl --user list-timers 'pfsentinel-*'
systemctl --user start pfsentinel-backup.service     # run once now to test
journalctl --user -u pfsentinel-backup.service -n 50

Desktop keyrings (GNOME Keyring, KWallet) stay locked until you log in, so a backup that runs before login cannot read the password. On a server or headless box, use SSH key auth or the encrypted file store. Without systemd, pfs schedule enable writes tagged crontab lines instead (check with crontab -l, log in ~/.pfsentinel/logs/scheduled.log).

Windows (Task Scheduler; open PowerShell with Run as administrator)

pfs schedule enable --daily-time 01:30 --no-weekly
pfs schedule status
Get-ScheduledTask -TaskPath '\pfSentinel\' | Get-ScheduledTaskInfo
Start-ScheduledTask -TaskPath '\pfSentinel\' -TaskName DailyBackup   # run once now to test

Tasks run while you are signed in (a locked screen is fine), wake the machine, run on battery, and catch up at the next sign-in after a missed run. LastTaskResult 0 means success.

ZFS snapshot backups

pfs backup snapshot-list -d home-fw
pfs backup snapshot -d home-fw --full    # first run: full stream
pfs backup snapshot -d home-fw           # later runs: incremental

To include snapshots in every pfs backup run (and scheduled runs), set backup_policy.zfs.enabled to true in config.json (open it with Linux: nano "$(pfs config path)"Windows: notepad (pfs config path)), then run pfs config validate. Defaults: dataset zroot/ROOT, incremental on, keep 3 snapshots on the device. On UFS installs use pfs backup archive -d home-fw instead.

Notifications to Telegram or Slack

pfs notify telegram setup
pfs notify slack setup
pfs notify status
pfs notify test

Pause a channel without losing credentials: pfs notify slack disable, later pfs notify slack enable. Skip notifications for one run: pfs backup run --no-notify.

Check schedule health

pfs schedule status
pfs status
pfs backup list -d home-fw --json
pfs backup search --date 2026-09-19

Linux: OS-level view

systemctl --user list-timers 'pfsentinel-*'
journalctl --user -u pfsentinel-backup.service --since today

Windows: OS-level view

Get-ScheduledTask -TaskPath '\pfSentinel\' | Get-ScheduledTaskInfo | Select-Object TaskName, LastRunTime, LastTaskResult, NextRunTime

If status warns that the schedule is enabled in config but nothing is installed, run pfs schedule enable again. A failed last result points at credentials or connectivity: run pfs config validate and pfs device test.

Restore a config to pfSense

pfs backup search -d home-fw --changes firewall
pfs backup diff FILE_A FILE_B
pfs backup verify FILE
pfs backup restore FILE --target config-restore.xml

Then in the pfSense web UI open Diagnostics > Backup & Restore, under Restore Backup choose "All" as the restore area, select config-restore.xml, and click Restore Configuration. pfSense reboots to apply it. pfSentinel never writes to the firewall; restoring is always a manual step you control.

Self-update

pfs update check
pfs update install
pfs update revert        # only if the new version misbehaves

Binary installs must be in a folder you can write to (~/.local/bin on Linux, %LOCALAPPDATA%\pfSentinel on Windows, as in Standalone binary). A copy in /usr/local/bin needs sudo pfs update install.

Troubleshooting

Use with an AI assistant

The button below copies a short instruction followed by this entire manual as plain text. Paste it into Claude, ChatGPT or another assistant, then ask your question. The assistant will ask for your OS and how you reach pfSense before suggesting commands.

Plain-text files for tools and crawlers: llms.txt (index) and llms-full.txt (full manual).