Documentation

Policy, objects & NAT

The eight rules every console screen obeys, the object catalog behind every field, and why NAT lives somewhere else.

The management UI is the product. These principles are binding on every screen, and each one exists because the alternative is a well-known source of firewall mistakes.

Firewall ▸ Rulespreview diffcommit (confirm 10m)
Threat control1 rule
any → any<rubix_blocklist> → any : anydrop#quick
LAN access2 rules
LAN → WANlan-net → any : anyacceptlog#egress
LAN → locallan-net → firewall : dnsaccept#infra
Published services1 rule
WAN → DMZany → web-server : httpsacceptlogIPS#inbound

Not an IP address in sight. Rename web-server and every rule that references it follows. Move an interface between zones and no rule is rewritten.

1. Objects, not addresses

Nothing in the console is a hand-typed address, port, interface or zone. Every such field picks from an object catalog: a built-in Any, per-interface address and network objects, predefined services, and whatever you define yourself. What the document stores is a reference, so renaming an object updates every rule that uses it and re-scoping one updates what those rules mean.

Object kindValueExample
IP hostA single IPv4 or IPv6 address10.0.0.5, 2001:db8::10
NetworkA subnet in CIDR10.0.0.0/24, 2001:db8::/64
IP rangeStart–end, same family10.0.0.5-10.0.0.9
DNS hostA hostname, resolved on the boxhost.example.com
ServiceProtocol and portstcp/443
MACA hardware addressfor address-based matching

2. Zones, not interfaces

Policy reads LAN → WAN, not em1 → em0. Moving an interface between zones never rewrites a rule, so re-cabling a site is a topology change rather than a policy migration. There is also a built-in local zone meaning the firewall itself, which is how you write rules about traffic to the box — its resolver, its console — without naming its addresses.

Firewall rules can also match applications by DNS NXDOMAIN and TLS SNI, and by Squid when TLS inspection is on. That is hostname and SNI matching — not full protocol decode.

3. NAT is separate from policy

Masquerade/source-NAT and port forwards get their own screens, in their own clearly separated sub-tabs, never interleaved with filter rules. Interleaving them is the single biggest source of firewall confusion, and the fix is structural rather than a documentation note.

4. Rules are organized, colored and tagged

  • Groups — titled, colored, collapsible sections such as "Guest WiFi" or "Published services", so a long ruleset stays scannable.
  • Color — a per-group accent, overridable per rule, drawn as the row's left border. Color carries meaning at a glance but never only color; the same information is in text.
  • Tags — free-form labels, with instant filtering by tag.

Groups, colors and tags are part of the document, and they render into the pf ruleset as traceable comments and rule labels — so the live ruleset maps back to the rows you see.

5. Preview before commit

Every change shows a diff of the rendered config and the services that will reload, before anything is applied. A commit can also arm a confirm window so a change that severs your own access reverts itself. How the pipeline works.

6. One click to a live log

Every service row has a Live button that streams that component's log. Each daemon logs through one local collector, which keeps a bounded in-memory ring buffer per service — so the viewer shows recent context instantly and then tails — and writes rotating files to disk for history. Remote syslog targets are configurable.

The live view supports pause and resume, a text filter, a severity filter and jump-to-now. Because firewall logging is per-rule, a live pf view can be filtered to one rule's label, which answers "is this rule matching?" in seconds instead of an SSH session.

ServiceSourceNotable events
pfpflog (pcap)Per-rule matches, default drops
FRRsyslogAdjacency up/down, route changes
strongSwansyslog / charonIKE negotiation, SA up/down
WireGuardkernelHandshakes, endpoint changes
KeasyslogLeases granted and expired
UnboundsyslogQueries, at the configured verbosity
SuricataEVE JSONAlerts and drops — also feeds the AI layer
Squidaccess logRequested URLs, allow/deny verdicts

7. Progressive disclosure

Common settings are visible; advanced settings fold away behind Advanced. A new admin should be able to do the 80% case without a manual — which is also the test we apply to any new screen.

8. Consistent verbs

Add, Edit, Clone, Disable and Delete mean the same thing on every screen. Disable — not delete — is always one click, because toggling a rule off is the most common troubleshooting step anyone performs on a firewall.