Wheelhouse docs

Firewall — rules#

The Rules view is one table of every rule in the selected address family, across the three base chains and every named ruleset, with nftables' packet and byte counts joined onto each row. Clicking a row opens an editor for that rule; + Add rule opens the same editor against an empty draft. Both write into the staging area, and both show you the commands before you stage them. This page is the field-by-field reference for what those commands are.

The table#

ColumnWhere it comes from
RulesetThe chain name (input, forward, output) or the named ruleset's name. A named ruleset carries a small set label; base chains are shown in the muted colour.
#The rule number. Sorted numerically, so 9 comes before 10.
Actionaction as a badge — green for accept, red for drop and reject, neutral for anything else — plus a disabled badge when the rule carries disable.
In / Outinbound-interface name and outbound-interface name, or any.
Source / DestinationThe literal address if there is one; otherwise the group as NAME (network), NAME (address), NAME (domain), NAME (mac); otherwise a mac-address; otherwise any. A port group is not shown here — it is not the address side of the match.
Protoprotocol, or any.
Packets / BytesFrom show firewall statistics, keyed by family, ruleset title and rule number. Blank — not zero — when the statistics read failed.
Descriptiondescription.

Two compatibility details are handled while the table is built, and are worth knowing because they change what you see:

  • Connection state has two spellings. VyOS 1.3 wrote state established enable — an object per state. 1.4 and later write state established as a multi-value leaf. The page reads both and writes the current form, so a rule imported from an older configuration displays correctly and is rewritten in the modern shape the first time you edit it.
  • A valueless node arrives three ways. log and disable can come back as null, {} or '' depending on the router. All three count as present; only the literal string disable is treated as "off".

The rule editor#

Clicking a row opens a side panel titled <ruleset> rule <number>. It has four parts:

  1. Live counters — the packets and bytes for this rule, from the same 5-second poll that feeds the table.
  2. Edit — the full field set, described below.
  3. This stages — the set and delete commands your edits have produced so far, updated as you type. Empty until you change something.
  4. Full config object — the rule exactly as the router returned it, as JSON. This is the escape hatch for anything the form does not model.

The footer has Stage n changes and Delete rule. Delete stages one operation:

delete firewall ipv4 forward filter rule 110

The panel is keyed by rule, so it is torn down and rebuilt when you click a different row. That is a fix, not an implementation detail: without the key, an edit begun on one rule was staged against the next one clicked.

Every field, and what it writes#

The base path is firewall <family> <chain> filter rule <number> for a base chain, or firewall <family> name <RULESET> rule <number> for a named ruleset. The table below shows what each control appends to it.

FieldCommand it stagesNotes
Action… action <accept\|drop\|reject\|jump\|return\|continue>jump writes no jump-target; see below.
Protocol… protocol <tcp\|udp\|tcp_udp\|icmp>The IPv6 list offers icmpv6 in place of icmp. Blank means any, and clearing it stages a delete.
Inbound interface… inbound-interface name <iface>
Outbound interface… outbound-interface name <iface>
Source address… source address <addr-or-cidr>Disabled while a source group is selected.
…or source group… source group <kind> <NAME>kind is address-group, network-group, domain-group, mac-group or the ipv6- variants.
Source port… source port <port-or-range>
Destination address… destination address <addr-or-cidr>Disabled while a destination group is selected.
…or destination group… destination group <kind> <NAME>
Destination port… destination port <port-or-range>Disabled while a port group is selected.
…or port group… destination group port-group <NAME>
Connection state… state established, … state related, … state new, … state invalidOne command per checked box; unchecking stages the matching delete.
Log matches… log
Disabled… disableThe rule stays in the configuration and is not loaded into nftables.
Description… description <text>A value containing a space is single-quoted in the preview and in the command.

Address-group selectors only offer groups that can be referenced from the current family: an ipv6-address-group is not listed on an IPv4 rule, because the commit failure for that mistake names neither the rule nor the group.

How the diff is computed#

Creating and editing use one function against one draft type. It walks the fields and emits:

  • nothing at all for a field you did not change;
  • a set when a field gained a value or changed;
  • a delete when a field that was set has been cleared — never a delete for a field that was already empty;
  • for the group-or-literal pairs, a delete of whichever form is being replaced followed by a set of the new one, because a group and a literal on the same side are mutually exclusive in the form;
  • one set per newly checked state and one delete per unchecked one.

Creating a rule is that same function run against an empty draft, which is why the two editors cannot drift apart: a rule this product can create is a rule it can change. The add panel used to offer nine fields where the row editor offered two, and this is the fix. (ui/src/pages/Firewall.tsx ruleOps)

Adding a rule#

+ Add rule opens the same field set with two extra controls at the top.

Ruleset lists the three base chains under Base chains, and every named ruleset in the current family under Named rulesets. The list is rebuilt per family, because named rulesets differ between families.

Rule number defaults to ten past the highest rule in the chosen ruleset, leaving gaps for later insertions the way the CLI's own examples do. The hint under the field shows the number that will be used if you leave it blank. Type your own and it is validated against ^[1-9]\d{0,5}$ — 1 to 999999 — with the error shown inline (ui/src/lib/format.ts RULE_NUMBER).

The "next free" number counts rules the panel has staged since the last commit as well as rules the router already has. The router's configuration does not change while operations sit in the staging area, so without that counter the second rule you added before committing reused the first one's number, and the two merged into one rule in the queue.

A worked example#

Permit established HTTPS to a web server on the LAN, from the internet, on a router whose forward chain defaults to drop. In the editor: ruleset forward, number left blank (offered as 110 here), action accept, protocol tcp, inbound interface eth1, destination address 192.0.2.10, destination port 443, log on, description https to the web server. The Commands block then reads:

set firewall ipv4 forward filter rule 110 action accept
set firewall ipv4 forward filter rule 110 protocol tcp
set firewall ipv4 forward filter rule 110 destination address 192.0.2.10
set firewall ipv4 forward filter rule 110 destination port 443
set firewall ipv4 forward filter rule 110 inbound-interface name eth1
set firewall ipv4 forward filter rule 110 log
set firewall ipv4 forward filter rule 110 description 'https to the web server'

Press Stage rule and those seven operations join the staging area. Nothing has reached the router yet. Open the Commit Bar, read the diff, and commit — with a confirm window, because the Commit Bar marks any path starting firewall as one that can cut you off.

Deleting and disabling#

Delete rule stages delete … rule <n> — the whole rule, in one operation.

The Disabled checkbox stages … disable, which keeps the rule in the configuration and out of nftables. Prefer it while you are proving that a rule is the one causing a problem: a disabled rule is still in the commit history and still in the diff, whereas a deleted one has to be retyped.

What this page will not do#

  • It will not reorder rules. Order is the rule number, and the only way to move a rule is to create it under a new number and delete the old one.
  • It will not complete a jump rule. The action list offers jump, return and continue, and the editor writes only action. A jump needs the name of the ruleset to jump to, and there is no field for it here.
  • It will not show you nftables. Counters are joined from show firewall statistics. A per-object view of the compiled ruleset is not built — nothing in the product renders it (agent/opmode.go handleFirewallStats).

See also#

Checked against#

ui/src/pages/Firewall.tsx, ui/src/lib/format.ts, ui/src/components/ui.tsx, agent/main.go, agent/opmode.go, agent/staging.go.

Updated 2026-09-02 manual firewall rules