Skip to main content

pfSense Package

Scaffold a pfSense package whose settings live in the WebGUI and whose background work runs as a quiet PHP command scheduled by pfSense.

Why Use This Command?

  1. Generates the standard pfSense package manifest, configuration XML, install hooks, packing list, and FreeBSD port metadata together.
  2. Connects WebGUI fields to a managed cron entry, keeping the scheduled command implementation separate from the user-facing settings.
  3. Stages the port with the current workspace version and includes a root GitHub Actions workflow that builds a .pkg file on FreeBSD and attaches it with a checksum to a GitHub release.
  4. Lints, type-checks, and tests the Node.js packaging helpers independently from the native pfSense and FreeBSD sources.

Requirements

  • Node.js runtime — Use Node.js 22 or 24 to validate and stage the package.
  • FreeBSD package builder — A matching FreeBSD environment is required only for the final make package step. See Netgate's package build guidance.
  • Target version — Build against the FreeBSD major used by the pfSense release you support. The generated workflow reads the optional PFSENSE_FREEBSD_VERSION repository variable and defaults to 15.
  • Empty directory or monorepo root — Nova auto-detects whether to create a project or add a package.

Unofficial packages

Installing a .pkg file from GitHub bypasses Netgate's package repository review and support. Test on a disposable or backed-up firewall before production use. To pursue official distribution, follow Netgate's package development process.

Usage

Options

FlagDescription
-d, --dry-runRun without writing any files.
--name <name>Project slug when creating a new monorepo; omit at an existing root.
--non-interactiveRequire every answer as a flag and do not open prompts.
--workspace-name <name>Workspace directory name; Nova adds pfsense-pkg- to the workspace package.
--output <dir>Output directory.

Output Files

File or DirectoryDescription
port/Makefile.templateFreeBSD port recipe with a build-time workspace-version placeholder.
port/pkg-descr and port/pkg-plistPackage description and installed-file inventory.
port/files/pkg-install.in and port/files/pkg-deinstall.inStandard pfSense package lifecycle hooks.
port/files/usr/local/pkg/<name>.xmlWebGUI menu, settings fields, validation, and package lifecycle callbacks.
port/files/usr/local/pkg/<name>.incSettings lookup and pfSense-managed cron synchronization.
port/files/usr/local/sbin/<name>Non-interactive PHP task invoked by cron.
port/files/usr/local/share/pfSense-pkg-<Name>/info.xmlpfSense package manifest.
scripts/check-package.mjsCross-platform structural validation.
scripts/stage-package.mjsCopies the port into build/port and stamps the package.json version.
scripts/build-package.shRuns make package in a supplied pfSense FreeBSD-ports checkout.
tests/project.test.tsVitest smoke suite for Nova-managed Node.js helper tooling.
tsconfig.*.json and vitest.config.mtsStrict helper and test contracts, separate from native package sources.
.github/workflows/pfsense-<name>.yml at the project rootBuilds on FreeBSD and uploads the .pkg plus checksum to a GitHub release.
package.jsonNova lifecycle commands and workspace metadata.

WebGUI and Scheduled Task

The generated page appears under Services > <Workspace Title>. It provides an enable switch, hourly/daily/weekly schedule, and starter message field. Saving the page removes any older matching cron entry and installs the selected schedule through pfSense's install_cron_job() API.

The executable under usr/local/sbin is intentionally not an interactive end-user CLI. Cron invokes it without arguments, it reads the saved pfSense configuration, and the starter implementation writes the configured message to the system log. Replace that final operation with the package's actual background work.

Check, Stage, and Package

bash
npm run check
npm run build
PFSENSE_PORTS_DIR=/path/to/pfSense-FreeBSD-ports npm run deploy

npm run build is safe on macOS, Linux, and Windows because it only stages source files. npm run deploy requires FreeBSD and refuses to overwrite an existing port directory in the supplied ports checkout.

Before publishing, replace the starter [email protected] value and confirm the MIT port license matches the repository.

GitHub Releases

The companion workflow runs when a GitHub release is published. It can also be run manually with the tag of an existing release. The workflow:

  1. Validates and stages the port on the GitHub runner.
  2. Starts a FreeBSD VM, checks out the pfSense ports framework, and runs the package build.
  3. Uploads the .pkg and .sha256 files as both workflow artifacts and assets on the selected GitHub release.

Set the PFSENSE_FREEBSD_VERSION repository variable to the FreeBSD major that matches the target pfSense release. If that FreeBSD version is not offered by the generated VM action, run scripts/build-package.sh on a matching pfSense builder instead; do not publish a package built against a different major.

Non-Interactive Mode

bash
nova scaffold package pfsense --non-interactive --name my-firewall-tools --workspace-name scheduler --output ./my-firewall-tools
nova scaffold package pfsense --non-interactive --workspace-name scheduler --output ./packages/scheduler

Naming and Registration

Nova prefixes the workspace package name with pfsense-pkg- when needed, so workspace scheduler becomes pfsense-pkg-scheduler. The FreeBSD port and installed package use pfSense's conventional pfSense-pkg-Scheduler form.

The workspace is registered with the package role and distributable policy so Nova can track its changelog and semantic version. Publication remains explicit: the generated workflow uploads the FreeBSD package to GitHub Releases and does not publish it to npm or Netgate's repository.