NATS subjects
Every request pfCentral sends to a firewall goes to a subject of the form:
pfsense.<device_id>.<resource>.<action>pfsense.4c4c4544-0042-5a10-8048-b4c04f4d3132.firewall.rules.listThe agent answers these as a NATS micro service named pfsense-agent. Each agent may only use subjects that start with its own pfsense.<device_id>., so one firewall can never answer, or listen to, another firewall’s requests. New to subjects? Read NATS for firewall admins first; it has an interactive subject explorer.
The tables below list the subjects by area. In each, * stands for the usual list, get, create, update and delete. The Subjects panel on the firewall’s Services → pfCentral → Status page lists every subject that agent answers.
Firewall
Section titled “Firewall”| Subject | Resource |
|---|---|
firewall.aliases.* | Alias list / get / create / update / delete / apply |
firewall.rules.* | Firewall rule list / get / create / update / delete / apply |
firewall.nat.portforward.* | Port forward CRUD |
firewall.nat.outbound.* | Outbound NAT CRUD |
firewall.nat.onetoone.* | 1:1 NAT CRUD |
firewall.schedules.* | Schedules CRUD + apply + active status |
firewall.states.* | Live state table: list with GUI filters / get by ID / delete by source-destination address pair |
firewall.traffic-shaper.* | ALTQ shapers and limiter pipes |
firewall.traffic-shaper.child-queues.* | ALTQ child queue CRUD under a root shaper queue (HFSC service curves, priority, bandwidth share) |
firewall.traffic-shaper.limiter.child-queues.* | Dummynet queue CRUD under a limiter pipe (mask, weight, AQM parameters) |
firewall.virtual-ips.* | Virtual IP CRUD + apply |
Interfaces
Section titled “Interfaces”| Subject | Resource |
|---|---|
interfaces.assignments.* | Interface assignment CRUD |
interfaces.vlans.* | VLAN CRUD |
interfaces.bridges.* | Bridge CRUD |
interfaces.gres.* | GRE tunnel CRUD |
interfaces.groups.* | Interface group CRUD |
interfaces.laggs.* | LAGG CRUD |
Routing
Section titled “Routing”| Subject | Resource |
|---|---|
routing.gateways.* | Gateway CRUD + default gateway get/update |
routing.gateway-groups.* | Gateway group CRUD |
routing.static-routes.* | Static route CRUD |
routing.apply | Apply routing changes |
Services
Section titled “Services”| Subject | Resource |
|---|---|
services.list / services.get / services.control | Service discovery and start/stop/restart |
services.dns-resolver.* | Unbound settings, host/domain overrides, access lists, apply |
services.dns-forwarder.* | dnsmasq host overrides CRUD + apply |
services.dhcp-server.* | DHCP server config, static mappings, address pools, custom options |
services.ntp.* | NTP settings and servers |
services.ssh.* | SSH daemon settings |
services.cron.* | Cron job CRUD |
Status
Section titled “Status”| Subject | Resource |
|---|---|
status.gateways | Gateway status |
status.interfaces | Interface status |
status.carp | CARP status |
status.dhcp-leases | DHCP leases |
status.logs.* | Firewall, DHCP, auth, and OpenVPN logs |
status.openvpn.* | OpenVPN servers, clients, connections |
system.status | System summary |
system.logs | System logs |
system.settings | System settings |
System
Section titled “System”| Subject | Resource |
|---|---|
system.hostname.update | Set hostname |
system.config.export | Read the complete saved active configuration, including secrets; not a historical backup |
system.dns.update | Set DNS servers |
system.timezone.update | Set timezone |
system.console.get | Console menu and serial console settings |
system.console.update | Replace and apply console settings |
system.tunables.* | Sysctl tunable CRUD |
system.certificate-authorities.* | Certificate authority list / get / create (internal, intermediate, import) / delete; delete is refused while the CA is in use; private keys are never returned |
system.certificates.* | Certificate list / get / create (internal signed by a CA, import) / delete; delete is refused while the certificate is in use; private keys are never returned |
system.packages.* | Installed package list, available packages, install / delete |
system.info | System info |
system.upgrade | Download a new agent binary and restart the agent (not a pfSense upgrade) |
Active configuration export contract
Section titled “Active configuration export contract”pfsense.<device_id>.system.config.export takes the normal request envelope with an empty payload: {"request_id":"…","payload":{}}. On success, the normal response envelope contains data: {"content":"<base64-encoded active XML bytes>"}. The byte payload preserves the file’s encoding; HTTP clients receive the decoded raw XML, not base64. The agent reads its configured active path (/cf/conf/config.xml by default), not /cf/conf/backup. There is no timestamp or caller-supplied path. An unreadable file returns error: {"code":503,"message":"active configuration unavailable","source":"pfsense"} with no file contents or path details.
The server treats this as an uncached, read-only request. It does not write the reply to the shared response cache or invalidate other cached configuration. The JSON reply must fit one broker message. There is no chunking, encryption of the export file, redaction, apply, history creation or restore. HTTP access requires admin or owner; direct NATS clients remain governed by broker credentials and subject permissions, not HTTP roles.
| Subject | Resource |
|---|---|
vpn.ipsec.phase1.* / vpn.ipsec.phase2.* | IPsec tunnel phases CRUD (Phase 1 includes encryption proposals) + apply |
vpn.openvpn.servers.* | OpenVPN server CRUD |
vpn.openvpn.clients.* | OpenVPN client CRUD (list omits keys and passwords) |
vpn.openvpn.cso.* | OpenVPN client-specific overrides |
vpn.openvpn.apply | Resync OpenVPN servers, clients, and client-specific overrides |
vpn.wireguard.tunnels.* / vpn.wireguard.peers.* | WireGuard tunnels and peers CRUD |
vpn.wireguard.settings.* | WireGuard global settings |
Diagnostics
Section titled “Diagnostics”| Subject | Resource |
|---|---|
diagnostics.ping | Run ping from the device |
diagnostics.traceroute | Trace an IPv4 route with a bounded hop count |
diagnostics.dns-lookup | Query a DNS record using drill on the device |
diagnostics.command | Run a diagnostic command |
diagnostics.reboot / diagnostics.halt | Reboot or halt the device |
diagnostics.arp.* | ARP table list / delete |
diagnostics.config-history.* | List, read and delete pfSense’s own config backups in /cf/conf/backup |
diagnostics.tables.* | pf tables list / get / delete entry |
diagnostics.packet-capture.start | Start a bounded packet capture |
diagnostics.packet-capture.status | Read the current capture status |
diagnostics.packet-capture.stop | Stop a capture and keep the captured packets |
diagnostics.packet-capture.get | Download the completed capture as base64 PCAP bytes |
Traceroute and DNS Lookup require admin or owner in both the API and UI. Both bypass the shared state cache. The agent validates the arguments and runs the executable directly, not through a shell. Each run has a 35-second deadline, up to 5 seconds of process termination grace, and at most 64 KiB of combined stdout/stderr. The server waits up to 45 seconds for the answer.
| Subject | Payload | Data |
|---|---|---|
diagnostics.traceroute | {"host":"192.0.2.10","max_hops":10} | {"host","output","result_code"} |
diagnostics.dns-lookup | {"host":"example.com","record_type":"A","server":"192.0.2.53"} | {"host","output","result_code"} |
host is required. Traceroute accepts an IPv4 address or hostname. max_hops
defaults to 10 when omitted or zero and must otherwise be 1–30. It runs
traceroute -n -w 1 -q 1 -m <max_hops> <host>: numeric output, one probe per
hop and a one-second probe wait. IPv6 traceroute and source-interface selection
are not available.
DNS accepts ASCII DNS names (including underscore labels) or IP literals.
record_type is case-insensitive and defaults to A; allowed values are A,
AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV, and CAA. server is
optional; when present it must be an IPv4 or IPv6 address without a zone. Omit
it to use the firewall’s resolver configuration. The command is
drill <absolute-host> [@<server>] <record_type>. The agent adds a trailing
dot to the query name so drill cannot interpret names such as AXFR as type
tokens. For PTR, supply a reverse DNS name; an IP literal is not automatically
converted to one.
result_code is the process exit code, or -1 for a timeout, cancellation or
failure to start. A zero exit does not establish that the destination was
reached or the DNS answer exists: inspect hop output and the DNS response code
(NOERROR, NXDOMAIN, SERVFAIL). Invalid agent payloads return error code
400. Closing the browser does not cancel an agent request already in progress.
Packet captures require an admin or owner role in the API and UI. The agent runs
tcpdump without a shell or promiscuous mode, with limits of 30 seconds,
200 packets, and 2048 captured bytes per packet. One capture is kept in memory
per device; it expires 10 minutes after completion or is replaced by the next
capture. All capture requests bypass the shared state cache. The HTTP download
route returns a binary .pcap file. Captures may contain passwords and other
sensitive data; store downloaded files securely.
Users & auth (on-device)
Section titled “Users & auth (on-device)”| Subject | Resource |
|---|---|
users.* | pfSense user CRUD |
users.groups.* | pfSense group CRUD |
users.auth-servers.* | Auth server CRUD |
Messages the agent publishes
Section titled “Messages the agent publishes”| Subject | How often | Content |
|---|---|---|
pf.presence.<device_id> | Every 5 s | Heartbeat: device ID, name, site, agent version, IP address, model |
pfsense.<device_id>.telemetry.metrics | Every 2 s | Telemetry envelope: system vitals, interfaces, gateways, VPN and services |
In embedded mode pfCentral also listens to the broker’s own connect and disconnect events, so a firewall that closes its connection shows offline at once. See Online, offline and telemetry.
Agent permissions
Section titled “Agent permissions”The pass pfCentral signs for each agent allows:
| Subjects | |
|---|---|
| Publish | pfsense.<device_id>.>, pf.presence.<device_id>, $SRV.>, _R_.> |
| Subscribe | pfsense.<device_id>.>, _INBOX.>, $SRV.> |
$SRV.> is the standard micro service discovery ($SRV.PING, $SRV.INFO, $SRV.STATS). _INBOX.> and _R_.> carry replies.
JetStream streams and buckets
Section titled “JetStream streams and buckets”| Name | Kind | Keeps |
|---|---|---|
TELEMETRY | Stream on pfsense.*.telemetry.metrics | 6 hours, on disk |
device-presence | Key-value bucket | One entry per online device; expires after 15 s without a heartbeat |
device-state | Key-value bucket | Recent lists from each device, for fast page loads; expire after 5 minutes (PFCENTRAL_STATE_CACHE_TTL) |
With an external broker and PFCENTRAL_NATS_RESOURCE_PREFIX set, the names get that prefix, for example prod-TELEMETRY.
Timeouts
Section titled “Timeouts”pfCentral waits 5 seconds for each reply. If no agent answers (the device is offline), the request fails at once with “no responders”.