| |

LFCE 77 ๐Ÿง nftables โ€” Fundamentals

โฑ๏ธ Estimated read: 13 min | |

nftables is the modern packet-filtering framework that replaces iptables, ip6tables, arptables, and ebtables with a single tool. The previous chapters covered iptables, which is now a compatibility layer on top of the nftables kernel subsystem on most distributions . The LFCE exam expects the candidate to know the firewall framework that the distribution actually uses, and on Debian, Ubuntu, RHEL, and their derivatives, that framework is nftables. The nft command is the userspace utility, and the kernel subsystem is nf_tables . The syntax is different from iptablesโ€”it is inspired by tcpdumpโ€”and the table and chain model is more flexible, but the concepts are the same: tables group chains, chains contain rules, and rules match packets and apply verdicts.

The fundamental difference from iptables is that nftables has no predefined tables or chains. In iptables, the filter table and the INPUT, OUTPUT, and FORWARD chains exist whether the administrator uses them or not. In nftables, the administrator creates only the tables and chains that the configuration needs . This reduces the overhead of unused hooks and allows a single table to contain chains attached to different hooks with different priorities. The inet family, which sees both IPv4 and IPv6 traffic, is the recommended family for a host firewall because it eliminates the need for separate iptables and ip6tables rulesets .

Key point: An nftables table is a container for chains, and a chain is attached to a Netfilter hook with a type and a priority. The chain type determines what the chain can do: filter for filtering, nat for address translation, and route for rerouting. The hook determines where in the packet’s journey the chain is evaluated: prerouting, input, forward, output, or postrouting. The priority determines the order in which multiple chains on the same hook are evaluated . A rule consists of expressions that match packet fields, followed by statements that apply a verdict or an action. A single rule can have multiple statements, which is a capability that iptables does not have .


Why nftables replaces iptables

The single-tool problem.

iptables has separate tools for each protocol family: iptables for IPv4, ip6tables for IPv6, arptables for ARP, and ebtables for Ethernet bridging. Each tool has its own syntax and its own set of tables. nftables replaces all of them with the single nft command, and the inet family handles IPv4 and IPv6 traffic in the same chain . A rule that matches tcp dport 22 applies to both IPv4 and IPv6 packets, which eliminates the need to duplicate every rule.

The pre-defined-chain problem.

iptables registers the filter, nat, and mangle tables and their chains at boot, whether or not the administrator uses them. The unused chains still consume resources, and the hardcoded priorities of the hooks cannot be changed. nftables creates no tables or chains by default. The administrator defines exactly the objects that the firewall needs, and the chain priorities are configurable . This is a significant change: the INPUT chain in iptables is a hardcoded hook, while the input chain in nftables is a base chain that the administrator creates and attaches to the input hook.

The multi-statement problem.

An iptables rule has one target: ACCEPT, DROP, LOG, or a custom chain. To log a packet and then drop it, the administrator needs two rules, and the first must be a LOG rule that matches the same criteria as the second. An nftables rule can have multiple statements: it can log the packet, increment a counter, and drop it in the same rule . This reduces the number of rules and makes the intent clearer.


a. Tables, chains, and the nft command

The nft command is the userspace utility. It can be run interactively, with commands as arguments, or as an interpreter for a configuration file. The -f option reads a file, and the -i option starts an interactive session .

# List the current ruleset
sudo nft list ruleset

# List the tables
sudo nft list tables

# Add a table
sudo nft add table inet filter

# Add a chain to the table
sudo nft add chain inet filter input { type filter hook input priority 0\; policy drop\; }

The add table inet filter command creates a table named filter in the inet family. The add chain inet filter input command creates a chain named input in that table, attaches it to the input hook, and sets the policy to drop . The backslash before the semicolon is required because the shell interprets the semicolon as a command separator; the nft interactive mode or a quoted command avoids the escaping.

The chain type and hook are the key parameters. The type filter means the chain filters packets. The hook input means the chain sees packets destined for the local host. The priority 0 means the chain is evaluated at the default priority. The policy drop means the chain’s default verdict is to drop packets that do not match any rule .


b. Rules and expressions

A rule is a sequence of expressions followed by statements. The expressions match packet fields, and the statements apply verdicts or actions. The expressions are evaluated from left to right, and the rule matches if all expressions match.

# Allow SSH from a specific network
sudo nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 22 accept

# Allow HTTP and HTTPS
sudo nft add rule inet filter input tcp dport { 80, 443 } accept

# Allow established and related connections
sudo nft add rule inet filter input ct state established,related accept

The ip saddr 192.168.1.0/24 expression matches the source address, and the tcp dport 22 expression matches the destination port. The accept statement is the verdict. The tcp dport { 80, 443 } expression uses an anonymous set to match either port . The ct state established,related expression matches the connection state, which is the equivalent of iptables’ -m conntrack --ctstate ESTABLISHED,RELATED.

The statements can be combined. A rule can log a packet, count it, and drop it in the same line.

# Log and drop invalid packets
sudo nft add rule inet filter input ct state invalid log prefix "invalid: " drop

The log prefix "invalid: " statement logs the packet with the specified prefix, and the drop statement drops it. The two statements are in the same rule, which is not possible in iptables .


c. The configuration file and persistence

The nftables configuration is typically stored in /etc/nftables.conf. The file uses the same syntax as the nft command, and the nft -f option applies it. The file should begin with a flush ruleset command to clear the existing rules, because the declarative syntax appends rules rather than replacing them .

# /etc/nftables.conf
#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # Allow loopback
        iif lo accept

        # Allow established and related
        ct state established,related accept

        # Allow SSH from the local network
        ip saddr 192.168.1.0/24 tcp dport 22 accept

        # Allow HTTP and HTTPS
        tcp dport { 80, 443 } accept
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

The flush ruleset command clears the entire configuration, including all tables and chains. The table inet filter block defines the table, and the chain input block defines the base chain with its type, hook, priority, and policy. The rules inside the chain are the same as the command-line rules . The file is applied with sudo nft -f /etc/nftables.conf, and the nftables.service systemd unit restores it at boot.

The include directive allows drop-in files, and the define directive allows symbolic variables.

define SSH_PORT = 22

table inet filter {
    chain input {
        tcp dport $SSH_PORT accept
    }
}

The define SSH_PORT = 22 creates a variable that can be referenced as $SSH_PORT in the rules. The variable is scoped to the file and any included files . This is useful for maintaining a consistent value across multiple rules.


Complete Example Session

# ============================================
# PART 1: LIST THE CURRENT RULESET
# ============================================
sudo nft list ruleset
# Output is empty if no rules are configured

# ============================================
# PART 2: CREATE A TABLE AND CHAIN
# ============================================
sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0\; policy drop\; }

# ============================================
# PART 3: ALLOW LOOPBACK
# ============================================
sudo nft add rule inet filter input iif lo accept

# ============================================
# PART 4: ALLOW ESTABLISHED AND RELATED
# ============================================
sudo nft add rule inet filter input ct state established,related accept

# ============================================
# PART 5: ALLOW SSH FROM THE LOCAL NETWORK
# ============================================
sudo nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 22 accept

# ============================================
# PART 6: ALLOW HTTP AND HTTPS
# ============================================
sudo nft add rule inet filter input tcp dport { 80, 443 } accept

# ============================================
# PART 7: VERIFY THE RULES
# ============================================
sudo nft list chain inet filter input
# Output shows the rules in order

# ============================================
# PART 8: SAVE THE CONFIGURATION
# ============================================
sudo nft list ruleset > /etc/nftables.conf
# Or use the configuration file syntax with flush ruleset

# ============================================
# PART 9: APPLY THE CONFIGURATION FILE
# ============================================
sudo nft -f /etc/nftables.conf

# ============================================
# PART 10: ENABLE THE SERVICE
# ============================================
sudo systemctl enable nftables
sudo systemctl start nftables

The ten parts demonstrate the nftables fundamentals: listing, creating a table and chain, allowing loopback, allowing established connections, allowing SSH, allowing HTTP and HTTPS, verifying, saving, applying the file, and enabling the service. The critical distinction from iptables is Part 2: the table and chain are created explicitly, and the chain’s type, hook, priority, and policy are set in the same command.


Quick Reference

nft Commands

CommandPurpose
nft list rulesetShow the entire ruleset
nft list tablesShow the tables
nft add table <family> <name>Create a table
nft add chain <family> <table> <chain> { ... }Create a chain
nft add rule <family> <table> <chain> <expr> <stmt>Add a rule
nft delete table <family> <name>Delete a table
nft flush rulesetClear everything
nft -f <file>Apply a configuration file

Families

FamilyTraffic
inetIPv4 and IPv6
ipIPv4 only
ip6IPv6 only
arpARP
bridgeBridging
netdevIngress/egress

Chain Types and Hooks

TypeHooksPurpose
filterprerouting, input, forward, output, postroutingFiltering
natprerouting, input, output, postroutingAddress translation
routeoutputRerouting

Common Expressions and Statements

Expression/StatementPurpose
ip saddr <addr>Match source address
tcp dport <port>Match destination port
ct state <state>Match connection state
iif <interface>Match input interface
acceptAccept the packet
dropDrop the packet
log prefix "<text>"Log the packet
counterCount the packet

Best Practices

โœ… Do This:

# Use the inet family for dual-stack
nft add table inet filter                                       # โœ…

# Set the chain policy explicitly
nft add chain inet filter input { type filter hook input priority 0\; policy drop\; } # โœ…

# Allow loopback first
nft add rule inet filter input iif lo accept                    # โœ…

# Allow established and related
nft add rule inet filter input ct state established,related accept # โœ…

# Use anonymous sets for multiple ports
nft add rule inet filter input tcp dport { 80, 443 } accept     # โœ…

# Flush the ruleset before applying a new configuration file
flush ruleset                                                   # โœ…

โŒ Don’t Do This:

# Assume the iptables chains exist
# nftables has no predefined tables or chains                    # โŒ

# Forget the chain type and hook
nft add chain inet filter input    # Regular chain; sees no packets # โŒ

# Apply a configuration file without flushing
# The rules are appended, not replaced                           # โŒ

# Mix iptables and nftables rules
# They conflict unless the iptables-nft compatibility layer is used # โŒ

# Use a space after the opening brace in the command
# The shell interprets the brace as a metacharacter              # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Rules not appliedChain not attached to a hookCreate a base chain with type and hook
Policy not enforcedChain policy not setAdd policy drop; to the chain
Configuration file appends rulesNo flush rulesetAdd flush ruleset at the top
Shell interprets bracesUnquoted metacharactersQuote the command or use nft -i
IPv6 not filteredUsed ip family onlyUse inet family

Real-World Examples

1. List ruleset

nft list ruleset

2. Create a table

nft add table inet filter

3. Create a chain

nft add chain inet filter input { type filter hook input priority 0\; policy drop\; }

4. Allow loopback

nft add rule inet filter input iif lo accept

5. Allow established

nft add rule inet filter input ct state established,related accept

6. Allow SSH

nft add rule inet filter input tcp dport 22 accept

7. Allow multiple ports

nft add rule inet filter input tcp dport { 80, 443 } accept

8. Log and drop

nft add rule inet filter input ct state invalid log prefix "invalid: " drop

9. Apply configuration

nft -f /etc/nftables.conf

10. Flush ruleset

nft flush ruleset

Visual

nftables Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  NO PREDEFINED TABLES OR CHAINS                              โ”‚
โ”‚                                                              โ”‚
โ”‚  iptables:                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ filter table (predefined)                              โ”‚  โ”‚
โ”‚  โ”‚ โ”œโ”€โ”€ INPUT chain (predefined)                           โ”‚  โ”‚
โ”‚  โ”‚ โ”œโ”€โ”€ FORWARD chain (predefined)                         โ”‚  โ”‚
โ”‚  โ”‚ โ””โ”€โ”€ OUTPUT chain (predefined)                          โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  nftables:                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ table inet filter (created by admin)                   โ”‚  โ”‚
โ”‚  โ”‚ โ”œโ”€โ”€ chain input (created by admin)                     โ”‚  โ”‚
โ”‚  โ”‚ โ”‚   type filter hook input priority 0; policy drop;    โ”‚  โ”‚
โ”‚  โ”‚ โ”œโ”€โ”€ chain forward (created by admin)                   โ”‚  โ”‚
โ”‚  โ”‚ โ”‚   type filter hook forward priority 0; policy drop;  โ”‚  โ”‚
โ”‚  โ”‚ โ””โ”€โ”€ chain output (created by admin)                    โ”‚  โ”‚
โ”‚  โ”‚     type filter hook output priority 0; policy accept; โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Chain Type, Hook, and Priority

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  A BASE CHAIN IS ATTACHED TO A HOOK WITH A TYPE AND PRIORITY โ”‚
โ”‚                                                              โ”‚
โ”‚  add chain inet filter input {                               โ”‚
โ”‚      type filter hook input priority 0; policy drop;         โ”‚
โ”‚  }                                                           โ”‚
โ”‚       โ”‚         โ”‚         โ”‚          โ”‚          โ”‚            โ”‚
โ”‚       โ”‚         โ”‚         โ”‚          โ”‚          โ””โ”€โ”€ default  โ”‚
โ”‚       โ”‚         โ”‚         โ”‚          โ””โ”€โ”€ order among chains  โ”‚
โ”‚       โ”‚         โ”‚         โ””โ”€โ”€ where in the packet path       โ”‚
โ”‚       โ”‚         โ””โ”€โ”€ what the chain can do                    โ”‚
โ”‚       โ””โ”€โ”€ family and table                                   โ”‚
โ”‚                                                              โ”‚
โ”‚  Multiple chains on the same hook are evaluated by priority. โ”‚
โ”‚  Lower priority numbers are evaluated first.                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Configuration File

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  /etc/nftables.conf                                          โ”‚
โ”‚                                                              โ”‚
โ”‚  #!/usr/sbin/nft -f                                          โ”‚
โ”‚                                                              โ”‚
โ”‚  flush ruleset              โ† clear the existing rules       โ”‚
โ”‚                                                              โ”‚
โ”‚  table inet filter {                                         โ”‚
โ”‚      chain input {                                          โ”‚
โ”‚          type filter hook input priority 0; policy drop;     โ”‚
โ”‚                                                              โ”‚
โ”‚          iif lo accept                                      โ”‚
โ”‚          ct state established,related accept                 โ”‚
โ”‚          tcp dport { 22, 80, 443 } accept                    โ”‚
โ”‚      }                                                       โ”‚
โ”‚  }                                                           โ”‚
โ”‚                                                              โ”‚
โ”‚  Apply with: nft -f /etc/nftables.conf                       โ”‚
โ”‚  Restore at boot: systemctl enable nftables                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Userspace toolnft
Kernel subsystemnf_tables
Default tables/chainsNone
Recommended familyinet (dual-stack)
Chain typesfilter, nat, route
Hooksprerouting, input, forward, output, postrouting
Configuration file/etc/nftables.conf
Apply filenft -f /etc/nftables.conf
Flush rulesetflush ruleset
Servicenftables.service
Multi-statement ruleYes
Built-in setsYes

Key takeaways:

  • nftables replaces iptables as the default firewall framework. It uses a single nft tool for all protocol families, and the inet family handles IPv4 and IPv6 traffic in the same chain . iptables is now a compatibility layer on top of nftables on most distributions.
  • There are no predefined tables or chains. The administrator creates exactly the tables and chains that the configuration needs. A base chain is attached to a hook with a type and a priority, and the chain policy determines the default verdict .
  • A single rule can have multiple statements. An nftables rule can match a packet, log it, count it, and drop it in the same line. iptables requires separate rules for each action .
  • The inet family handles dual-stack. A rule that matches tcp dport 22 applies to both IPv4 and IPv6 packets, which eliminates the need to duplicate rules for each protocol family .
  • The configuration file must flush the ruleset first. The declarative syntax appends rules rather than replacing them. The flush ruleset command clears the existing configuration, and the table block defines the new one .
  • The nft -f command applies a configuration file. The nftables.service systemd unit restores the file at boot. The service must be enabled with systemctl enable nftables .

Remember: nftables is the modern firewall framework. The nft command is the tool, and the inet family is the recommended scope. The administrator creates the tables and chains, attaches the chains to hooks with types and priorities, and adds rules with expressions and statements. A rule can have multiple statements, and the configuration is stored in /etc/nftables.conf with a flush ruleset at the top. The service restores the configuration at boot. The syntax is different from iptables, but the concepts are the same: match the packet, apply the verdict, and order the rules so that the specific ones are evaluated before the general ones.


Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!