nft Command in Linux: nftables Rules, Tables & Chains (RHEL/Fedora/Rocky)

nft is the userspace CLI for the Linux nftables firewall framework. Define tables, chains, and rules in the netfilter stack — list the live ruleset, load rule files, and debug filtering alongside firewalld on RHEL-family systems.

Published

Updated

Read time 11 min read

Reviewed byDeepak Prasad

nft Command in Linux: nftables Rules, Tables & Chains (RHEL/Fedora/Rocky)
About nft is the userspace CLI for the Linux nftables firewall framework. Define tables, chains, and rules in the netfilter stack — list the live ruleset, load rule files, and debug filtering alongside firewalld on RHEL-family systems.
Tested on Rocky Linux 10.2 (Red Quartz); nftables v1.1.5; kernel 6.12.0-211.28.1.el10_2.x86_64
Man page nft(8)
Privilege root / sudo
Distros

RHEL 8+, Rocky Linux, AlmaLinux, Fedora, Debian, and Ubuntu (nftables framework; RHEL 8+ uses nftables as the netfilter backend).

Zone-based host firewall on RHEL: firewalld (firewall-cmd).

Ubuntu desktop shortcut: ufw.

Related guide

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):

text
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 JSON

nft 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:

bash
sudo nft list tables

Sample output:

text
table inet firewalld
table inet netavark

List the start of the firewalld table:

bash
sudo nft list table inet firewalld 2>&1 | head -15

Sample output:

text
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:

bash
sudo nft add table inet glctest

Add a chain and rule:

bash
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 accept

Verify:

bash
sudo nft list table inet glctest

Sample output:

text
table inet glctest {
	chain input {
		type filter hook input priority filter; policy accept;
		tcp dport 8080 accept
	}
}

Remove the lab table when finished:

bash
sudo nft delete table inet glctest
Common 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:

bash
sudo nft --numeric --numeric-protocol list ruleset 2>&1 | head -12

Sample output:

text
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:

bash
cat <<'EOF' > /tmp/glctest.nft
table inet glclab {
  chain output {
    type filter hook output priority 0; policy accept;
  }
}
EOF

Check without applying:

bash
sudo nft -c -f /tmp/glctest.nft

Load for real:

bash
sudo nft -f /tmp/glctest.nft
sudo nft list table inet glclab

Sample output:

text
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:

bash
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 glchandle

Sample output:

text
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):

bash
sudo nft delete rule inet glchandle input handle 4
sudo nft delete table inet glchandle

If 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:

bash
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 forward

Sample output:

text
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:

bash
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 blocklist

Sample output:

text
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:

bash
sudo nft -j list table inet firewalld 2>&1 | head -8

Sample output:

text
{ "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
  • You need direct control over netfilter tables, chains, hooks, sets, and maps
  • You maintain hand-written .nft rule files or configuration management templates
  • You debug what firewalld or Podman actually installed in the kernel
  • You build routers, NAT, or forwarding policy beyond simple allow/deny ports
  • You migrate legacy iptables-nft scripts to native nft syntax
  • You want zone-based host firewall on RHEL with services and rich rules → firewalld
  • You want a simple Ubuntu desktop firewall CLI → ufw
  • Your team still runs legacy iptables-save format only — consider iptables-nft translation or a controlled migration
  • You only need to observe packets, not filter → tcpdump
  • You are on a host where nftables is disabled and another stack owns the NIC — check nft list tables first

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.


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:

bash
sudo nft list ruleset > /etc/nftables/ruleset.nft
sudo systemctl enable nftables

On 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:

bash
sudo nft --handle list chain inet TABLE CHAIN

Note the # handle N comment, then:

bash
sudo nft delete rule inet TABLE CHAIN handle N

Flushing (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

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …