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.
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 --versionWindows (PowerShell)
py -m pip install pfsentinel
pfs --versionLinux: 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 --versionWindows (PowerShell)
py -m pip install --user pipx
py -m pipx ensurepath # then open a new terminal
pipx install pfsentinel
pfs --versionStandalone 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 terminalWindows (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 --versionThe 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 --versionWindows (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 --versionQuick 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
| What | Where |
|---|---|
| Config file | Linux: ~/.pfsentinel/config.jsonWindows: %USERPROFILE%\.pfsentinel\config.json (print with pfs config path) |
| Pinned SSH host keys | Linux: ~/.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 tokens | Linux: 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 jobs | Linux: 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 log | Linux: 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
| Option | Description |
|---|---|
--version, -v | Show version |
--install-completion | Install shell completion for the current shell |
--show-completion | Print the completion script |
--help | Show 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-browseronly 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.
| Option | Description |
|---|---|
--device, -d ID | Device ID (default: all enabled devices) |
--desc TEXT | Description label |
--backup-dir, -o PATH | Override backup directory (default: ~/Documents/pfSentinel, the same on both systems) |
--no-notify | Suppress notifications |
--area NAME | Back 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-packages | Exclude package config (HTTPS only) |
--include LIST | Extra targets, repeatable or comma-separated: rrd, pkg, dhcp, aliases, certs, logs |
--all-extras | Include all extra targets |
--config-only | Only the XML config, skip extras |
--non-interactive | Never 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.
pfs backup search
| Option | Description |
|---|---|
--name, -n TEXT | Filename substring |
--device, -d ID | Filter by device |
--date YYYY-MM-DD | Filter by date |
--changes TEXT | Filter by change label substring (for example firewall) |
--min-size KB, --max-size KB | Size range in KB |
--json | Output 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;
--fullforces 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).
--dirstakes 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.
| Option | Description |
|---|---|
--id TEXT | Device ID slug (for example home-fw) |
--label TEXT | Display name |
--host TEXT | IP address or hostname |
--method TEXT | ssh, https or http |
--username, -u TEXT | pfSense username |
--ssh-port INT | Default 22 |
--https-port INT | Default 443 |
--http-port INT | Default 80 |
--no-verify-ssl | Skip 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.
--forceoverwrites 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 inconfig.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.
| Option | Description |
|---|---|
--daily-time HH:MM | Daily backup time (default 02:00) |
--weekly-day DAY | Weekly backup day (default sunday) |
--weekly-time HH:MM | Weekly backup time (default 03:00) |
--no-weekly | Disable the weekly backup |
--task-scheduler / --no-task-scheduler | Use the OS scheduler (default). --no-task-scheduler runs in-process and stops when the command exits |
- Windows: Task Scheduler tasks
pfSentinel\DailyBackupandpfSentinel\WeeklyBackup. Run from an Administrator PowerShell. Tasks run while you are signed in (a locked screen counts); a missed run starts at the next sign-in. - Linux with systemd: user timers
pfsentinel-daily.timerandpfsentinel-weekly.timer. Missed runs start at next boot. Enable lingering once to run while logged out:loginctl enable-linger $USER. - No systemd (WSL without systemd, containers, macOS): tagged crontab lines; the rest of your crontab is left alone.
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 runpfs notify telegram setupand paste the token; the chat ID is auto-detected.disablekeeps 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 runpfs notify slack setup.disablekeeps 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-fwSSH 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.pubWindows (PowerShell, built-in OpenSSH client)
ssh-keygen -t ed25519 -C "pfsentinel" -f $env:USERPROFILE\.ssh\pfsentinel_ed25519
Get-Content $env:USERPROFILE\.ssh\pfsentinel_ed25519.pub2. 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-fwWindows (PowerShell)
pfs device edit home-fw # SSH private key path: C:\Users\YOU\.ssh\pfsentinel_ed25519
pfs device test -d home-fwFor 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"; doneNightly 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 50Desktop 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 testTasks 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: incrementalTo 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 testPause 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-19Linux: OS-level view
systemctl --user list-timers 'pfsentinel-*'
journalctl --user -u pfsentinel-backup.service --since todayWindows: OS-level view
Get-ScheduledTask -TaskPath '\pfSentinel\' | Get-ScheduledTaskInfo | Select-Object TaskName, LastRunTime, LastTaskResult, NextRunTimeIf 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.xmlThen 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 misbehavesBinary 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
- SSH connection refused: enable SSH on pfSense (System > Advanced > Admin Access > Secure Shell), then
pfs device test -d ID. - Host key unknown or changed: run
pfs device trust-key ID. If you did not reinstall or re-key the firewall, a changed key can mean a man-in-the-middle; check the fingerprint on the pfSense console first. - TLS certificate errors (HTTPS): pfSense ships a self-signed certificate. Use SSH, or add the device with
--no-verify-sslor change it withpfs device edit ID. - Scheduled task fails with
0x80070002: the task points at a pfs executable that is no longer there (moved, uninstalled, or registered by an older version). Re-runpfs schedule enablefrom an Administrator PowerShell, then checkpfs schedule status. - "Administrator privileges are required" on
pfs schedule enable: open PowerShell with Run as administrator and run it again. Only registering the task needs admin; backups run as your user. pfsis not recognized: open a new PowerShell window after installing (PATH changes only apply to new windows), or runpy -m pfsentinel.pfs: command not found:~/.local/binis not on your PATH yet. Runpipx ensurepath(or add it in~/.bashrc) and open a new terminal.- "externally-managed-environment" from pip: use
pipx install pfsentinelinstead. - Backup skipped, no changes: expected. Config backups are saved only when the config changed.
- Scheduled run cannot read the password on a Linux desktop: the desktop keyring is locked before login. Use SSH key auth or stay logged in.
- Still stuck? Open an issue with the output of
pfs --versionand the failing command.
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).