nft — quick reference
Inspect the ruleset
Read what the kernel is enforcing before you change anything.
| When to use | Command |
|---|---|
| Dump the entire live ruleset | sudo nft list ruleset |
| List all tables | sudo nft list tables |
| Show one table | sudo nft list table inet TABLE |
| Show rules with numeric IPs and ports | sudo nft --numeric --numeric-protocol list ruleset |
| Show rule handles (for delete/replace) | sudo nft --handle list table inet TABLE |
| Show nftables version | nft --version |
Tables and chains
| When to use | Command |
|---|---|
| Add a table (IPv4+IPv6) | sudo nft add table inet TABLE |
| Add a filter chain on input hook | sudo nft add chain inet TABLE input '{ type filter hook input priority 0; policy accept; }' |
| Delete a table and everything in it | sudo nft delete table inet TABLE |
| Flush all rules inside a table | sudo nft flush table inet TABLE |
| List chains in a table | sudo nft list chain inet TABLE CHAIN |
Rules
| When to use | Command |
|---|---|
| Allow TCP port 8080 on input | sudo nft add rule inet TABLE input tcp dport 8080 accept |
| Drop traffic from one subnet | sudo nft add rule inet TABLE input ip saddr 192.168.99.0/24 drop |
| Insert a rule at position 0 | sudo nft insert rule inet TABLE input position 0 tcp dport 22 accept |
| Delete rule by handle | sudo nft delete rule inet TABLE input handle HANDLE |
| Replace rule by handle | sudo nft replace rule inet TABLE input handle HANDLE tcp dport 8443 accept |
Load, check, and persist
| When to use | Command |
|---|---|
| Load rules from a file | sudo nft -f /path/to/rules.nft |
| Validate syntax without applying | sudo nft -c -f /path/to/rules.nft |
| Interactive rule entry | sudo nft -i |
| Save current ruleset to stdout | sudo nft list ruleset > /tmp/ruleset.nft |
| Enable nftables service (distro unit) | sudo systemctl enable --now nftables |
On RHEL hosts where firewalld is active, it owns tables such as inet firewalld. Add lab tables with distinct names; do not flush ruleset on production systems.
Sets, maps, and counters
| When to use | Command |
|---|---|
| Create an IPv4 address set | sudo nft add set inet TABLE blocklist '{ type ipv4_addr; flags interval; }' |
| Add an element to a set | sudo nft add element inet TABLE blocklist { 203.0.113.5 } |
| Match against a set in a rule | sudo nft add rule inet TABLE input ip saddr @blocklist drop |
| Add a named counter to a rule | sudo nft add rule inet TABLE input tcp dport 443 counter accept |
| List set contents | sudo nft list set inet TABLE SETNAME |
Help and debugging
| When to use | Command |
|---|---|
| Show nft options | nft --help |
| Echo commands as they are applied | sudo nft -e add table inet TABLE |
| JSON ruleset output | sudo nft -j list ruleset |
nft — command syntax
Synopsis from nft --help on Rocky Linux 10.2 (nftables v1.1.5):
Usage: nft [ options ] [ cmds... ]
Options (general):
-h, --help Show this help
-v, --version Show version information
Options (ruleset input handling):
-f, --file <filename> Read input from <filename>
-i, --interactive Read input from interactive CLI
-c, --check Check commands validity without applying
-e, --echo Echo what has been added or replaced
Options (ruleset list formatting):
-a, --handle Output rule handle
-n, --numeric Print fully numerical output
-j, --json Format output in JSONnft talks to the kernel through netlink. Rules you add with nft add are immediate (runtime) unless your distro saves them under /etc/nftables/ or /etc/sysconfig/nftables.conf and loads them at boot.
nft — command examples
Essential See the live ruleset firewalld and Podman use
Before editing firewall policy, dump what is already loaded — RHEL systems often have inet firewalld and inet netavark tables.
Run the command:
sudo nft list tablesSample output:
table inet firewalld
table inet netavarkList the start of the firewalld table:
sudo nft list table inet firewalld 2>&1 | head -15Sample output:
table inet firewalld {
flags owner,persist
chain mangle_PREROUTING {
type filter hook prerouting priority mangle + 10; policy accept;
jump mangle_PREROUTING_POLICIES
}
...
}The owner,persist flag means firewalld manages this table — use firewall-cmd for routine port changes; use custom inet tables for your own rules.
Essential Add a lab table, chain, and allow rule
Practice in an isolated table name so you do not disturb firewalld.
Run the commands:
sudo nft add table inet glctestAdd a chain and rule:
sudo nft 'add chain inet glctest input { type filter hook input priority 0; policy accept; }'
sudo nft add rule inet glctest input tcp dport 8080 acceptVerify:
sudo nft list table inet glctestSample output:
table inet glctest {
chain input {
type filter hook input priority filter; policy accept;
tcp dport 8080 accept
}
}Remove the lab table when finished:
sudo nft delete table inet glctestCommon List rules with numeric addresses and ports
Hostnames and service names in rules can hide the actual match criteria — numeric mode shows what the kernel evaluates.
Run the command:
sudo nft --numeric --numeric-protocol list ruleset 2>&1 | head -12Sample output:
table inet firewalld {
flags owner,persist
chain mangle_PREROUTING {
type filter hook prerouting priority -140; policy accept;
jump mangle_PREROUTING_POLICIES
}
...
}Priority values appear as numbers (-140 instead of mangle + 10), which helps when comparing hook order across chains.
Common Load rules from a file and validate first
Production rules belong in .nft files under /etc/nftables/ — use -c to dry-run syntax.
Create a test file:
cat <<'EOF' > /tmp/glctest.nft
table inet glclab {
chain output {
type filter hook output priority 0; policy accept;
}
}
EOFCheck without applying:
sudo nft -c -f /tmp/glctest.nftLoad for real:
sudo nft -f /tmp/glctest.nft
sudo nft list table inet glclabSample output:
table inet glclab {
chain output {
type filter hook output priority filter; policy accept;
}
}Delete the lab table and file when done: sudo nft delete table inet glclab && rm /tmp/glctest.nft.
Advanced Delete one rule by handle
Handles identify individual rules so you can remove one line without flushing the chain.
Add a disposable rule with a handle listing:
sudo nft add table inet glchandle
sudo nft 'add chain inet glchandle input { type filter hook input priority 0; policy accept; }'
sudo nft add rule inet glchandle input tcp dport 9090 accept
sudo nft --handle list table inet glchandleSample output:
table inet glchandle {
chain input {
type filter hook input priority filter; policy accept;
tcp dport 9090 accept # handle 4
}
}Delete by handle (replace 4 with the handle from your output):
sudo nft delete rule inet glchandle input handle 4
sudo nft delete table inet glchandleIf the handle number differs on your host, copy it from the # handle N comment in the list output.
Common Drop traffic from one source subnet
Inline drops are quick for lab ACLs; for production consider sets when the list grows.
Run the commands:
sudo nft add table inet glcdrop
sudo nft 'add chain inet glcdrop forward { type filter hook forward priority 0; policy accept; }'
sudo nft add rule inet glcdrop forward ip saddr 192.168.99.0/24 drop
sudo nft list chain inet glcdrop forwardSample output:
table inet glcdrop {
chain forward {
type filter hook forward priority filter; policy accept;
ip saddr 192.168.99.0/24 drop
}
}Clean up: sudo nft delete table inet glcdrop.
Advanced Block IPs with a set
Sets keep rules readable when many sources share one drop policy.
Run the commands:
sudo nft add table inet glcset
sudo nft add set inet glcset blocklist '{ type ipv4_addr; flags interval; }'
sudo nft 'add chain inet glcset input { type filter hook input priority 0; policy accept; }'
sudo nft add element inet glcset blocklist { 203.0.113.5, 203.0.113.6 }
sudo nft add rule inet glcset input ip saddr @blocklist drop
sudo nft list set inet glcset blocklistSample output:
table inet glcset {
set blocklist {
type ipv4_addr
flags interval
elements = { 203.0.113.5, 203.0.113.6 }
}
}Remove the table with sudo nft delete table inet glcset.
Advanced Export ruleset as JSON for tooling
Automation and auditors sometimes need machine-readable output.
Run the command:
sudo nft -j list table inet firewalld 2>&1 | head -8Sample output:
{ "nftables": [ { "metainfo": { "version": "1.1.5", "release": "Commodore Bullmoose #6", "json_schema_version": 1 } }, { "table": { "name": "firewalld", "family": "inet", "flags": [ "owner", "persist" ] ...Pipe to jq in scripts for filtering chains or counters.
nft — when to use / when not
| Use nft when | Use something else when |
|---|---|
|
|
nft vs firewalld
| nft | firewalld | |
|---|---|---|
| Layer | Low-level netfilter CLI | High-level zone and service manager |
| Syntax | Tables, chains, hooks, sets | --add-service, --add-port, zones |
| Backend on RHEL 8+ | Native | Generates nftables rules |
| Best for | Custom rules, routers, debugging | Day-to-day server firewall on RHEL |
See the firewalld cheat sheet for zone workflows. Use sudo nft list table inet firewalld to inspect what firewall-cmd pushed into the kernel.
Related commands
Tools in the same networking and firewall workflow.
| Command | One line |
|---|---|
| nft | nftables CLI (this page) |
| firewalld | Zone-based firewall on RHEL |
| ss | List listening sockets after rule changes |
| tcpdump | Capture packets to verify filtering |
Browse the full index in our Linux commands reference.
nft — interview corner
What is nftables and how does nft fit in?
nftables is the modern Linux kernel firewall framework in the netfilter stack. The nft command is its userspace CLI — you define tables (address families like inet), chains (attached to hooks such as input or forward), and rules (matches and actions like accept or drop).
On RHEL 8 and later, both firewalld and iptables-nft ultimately program nftables in the kernel. nft list ruleset shows the combined picture.
A strong answer is:
"nftables is the netfilter firewall framework; nft is the CLI to define tables, chains, and rules. On RHEL 8+ it's the backend even when you use firewalld day to day."
What happened to iptables?
Classic iptables used separate tools (iptables, ip6tables, arptables). nftables unifies them under nft with a cleaner grammar and faster rule updates.
RHEL still ships iptables-nft — iptables syntax translated to nftables — for compatibility. New work should use native nft rule files when you control the stack directly.
A strong answer is:
"iptables is the legacy interface; nftables replaces it in the kernel. RHEL provides iptables-nft for old scripts, but nft is the native CLI for new rules."
Do nft rules survive a reboot?
Rules added interactively with nft add are runtime only unless you save them. Distros load /etc/nftables.conf or /etc/sysconfig/nftables.conf through the nftables systemd unit.
Workflow:
sudo nft list ruleset > /etc/nftables/ruleset.nft
sudo systemctl enable nftablesOn firewalld-managed hosts, permanent policy lives in firewalld's config — not ad hoc nft add lines.
A strong answer is:
"Runtime nft changes disappear on reboot unless I save them to /etc/nftables and enable the nftables service — on RHEL servers firewalld owns persistence for host firewall policy."
How do you delete one rule without flushing a chain?
List with handles:
sudo nft --handle list chain inet TABLE CHAINNote the # handle N comment, then:
sudo nft delete rule inet TABLE CHAIN handle NFlushing (nft flush chain) removes every rule — handles are safer for surgical edits.
A strong answer is:
"I list with --handle, then delete rule by handle — that removes one line without flushing the whole chain."
What does the inet family mean?
inet is the IPv4+IPv6 dual-stack family — one table can filter both protocols. Older ip and ip6 families split them.
Most new host firewall tables use inet so you do not duplicate every rule for IPv4 and IPv6.
A strong answer is:
"inet is the dual-stack nftables family — I use it so one table covers IPv4 and IPv6 instead of maintaining parallel ip and ip6 tables."
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Operation not permitted |
Missing root | Prefix with sudo |
syntax error in chain line |
Shell metacharacters | Quote the chain definition: nft 'add chain inet t c { ... }' |
| Rules vanish after reboot | Runtime-only changes | Save to /etc/nftables/ and enable nftables.service |
inet firewalld conflicts |
firewalld owns the table | Change ports with firewall-cmd; use a separate table name for custom rules |
-n flag error on list |
Option order | Put options before the command: nft --numeric list ruleset |
flush ruleset dropped SSH |
Removed allow rule for port 22 | Restore from backup file; use console access; allow SSH before experimenting |
| Set match fails | Wrong set type or family | Match type ipv4_addr vs ipv6_addr; use @setname syntax in rules |
References
- nft man page{target="_blank" rel="noopener"} — nftables CLI reference
- nftables wiki{target="_blank" rel="noopener"} — upstream project documentation
- firewalld cheat sheet — high-level host firewall on RHEL
- ufw command cheat sheet — Ubuntu firewall front end
- Linux commands cheat sheet — full command index

