Skip to main content

NFTABLES

nftables is the modern Linux firewall framework that replaces legacy iptables in many distributions. It provides a unified and more efficient ruleset engine inside the kernel, along with a powerful user-space tool (nft) to define firewall policies, NAT, packet mangling, and filtering.

Compared to iptables, nftables offers:

  • A single unified ruleset model (instead of multiple separate tools like iptables, ip6tables, arptables)
  • Better performance and scalability for large rulesets
  • More expressive syntax and reusable objects (sets, maps, verdict maps)
  • Easier atomic updates (safer rule deployment)
Scope

This page focuses on understanding how nftables works, reading and writing common rules, and building safe baseline firewall configurations for servers.

Compatibility note

Some systems still use iptables commands with an nftables backend (iptables-nft). You may see both tools installed, but only one ruleset is truly authoritative depending on system configuration.

Where nftables Fits

nftables is enforced by the kernel Netfilter subsystem. The nft CLI manipulates the ruleset.

Core Concepts

Tables

A table groups rules by protocol family and purpose.

Common families:

FamilyDescription
----
inetWorks for both IPv4 and IPv6 (recommended for most servers)
ipIPv4 only
ip6IPv6 only
arpARP rules (rare for typical VPS hardening)
bridgeBridged traffic

Chains

Chains attach to Netfilter hooks. Common hooks:

HookTypical Use
inputTraffic destined to the local host
outputTraffic originating from the local host
forwardTraffic routed through the host

Chains can be:

  • Base chains: attached to a hook with a priority and policy
  • Regular chains: jumped into from other chains

Rules and Verdicts

Rules match packet fields and return a verdict:

  • accept
  • drop
  • reject
  • log
  • jump <chain>
  • return

Install and Enable nftables

Ubuntu / Debian

sudo apt update
sudo apt install nftables -y
sudo systemctl enable --now nftables

Check status:

sudo systemctl status nftables --no-pager

Inspect the Current Ruleset (Safe)

Show ruleset:

sudo nft list ruleset

List tables:

sudo nft list tables

List chains in a table:

sudo nft list chains inet filter

Baseline Firewall (Server Template)

The most common and maintainable pattern is an inet table with input, forward, and output base chains.

Example: Minimal baseline (SSH + HTTP/HTTPS)

Create a file:

sudo nano /etc/nftables.conf

Paste:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {

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

# Allow established/related traffic
ct state established,related accept

# Allow loopback
iif "lo" accept

# Allow ICMP/ICMPv6 (important for networking)
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept

# Allow SSH (customize port if needed)
tcp dport 22 accept

# Allow web
tcp dport { 80, 443 } accept

# Optional: log dropped packets (rate-limited)
limit rate 5/minute log prefix "nft drop: " flags all counter
}

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

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

Validate syntax:

sudo nft -c -f /etc/nftables.conf

Apply:

sudo nft -f /etc/nftables.conf

Persist at boot (service uses /etc/nftables.conf on many distros):

sudo systemctl enable --now nftables

Common Rules and Patterns

Allow from a trusted IP (SSH allow-list)

tcp dport 22 ip saddr 203.0.113.10 accept
tcp dport 22 drop

Rate limit SSH (basic abuse reduction)

tcp dport 22 ct state new limit rate 15/minute accept
tcp dport 22 drop

Block an IP or subnet

ip saddr 198.51.100.23 drop
ip saddr 198.51.100.0/24 drop

Allow a port range

tcp dport 3000-4000 accept

Match interface

iif "eth0" tcp dport 443 accept

Sets (Efficient for Many IPs)

Sets are one of the strongest nftables features. They allow efficient membership checks without writing many separate rules.

Example: Allow SSH only from a set of IPs

set ssh_allowlist {
type ipv4_addr;
elements = { 203.0.113.10, 198.51.100.12 }
}

tcp dport 22 ip saddr @ssh_allowlist accept
tcp dport 22 drop

Update a set live:

sudo nft add element inet filter ssh_allowlist { 203.0.113.99 }
sudo nft delete element inet filter ssh_allowlist { 198.51.100.12 }

NAT with nftables (Common VPS Routing Use)

NAT is usually implemented using a separate nat table.

Example: Masquerade (outbound NAT)

table ip nat {
chain postrouting {
type nat hook postrouting priority 100;
oif "eth0" masquerade
}
}

Apply:

sudo nft -f /etc/nftables.conf

Enable IP forwarding:

sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-ipforward.conf
sudo sysctl --system

Logging and Counters

Log and count matches:

tcp dport 22 counter accept

Rate-limited logging:

limit rate 5/minute log prefix "nft: " flags all counter

Migration Notes (iptables to nftables)

Many systems run iptables using the nft backend. Key points:

  • iptables -S shows legacy-style rules, but they may map into nft internally
  • UFW may still manage iptables-style chains even when nft backend exists
  • If using UFW, do not simultaneously manage /etc/nftables.conf unless you fully control the design and understand the interaction
Avoid mixed control planes

Pick one firewall manager:

  • UFW (simple host firewall management), or
  • native nftables (full control) Mixing them can cause rule conflicts and unpredictable behavior.

Troubleshooting

View active ruleset

sudo nft list ruleset

Check service status

sudo systemctl status nftables --no-pager

Validate config without applying

sudo nft -c -f /etc/nftables.conf

Common issues

SymptomLikely CauseFix
---
Locked out over SSHSSH not allowed before policy dropAdd SSH allow first; use console recovery
Rules not persistent after rebootnftables service not enabled or config not usedenable service; verify /etc/nftables.conf
ICMP blocked (network issues)ICMP rules missingallow ICMP/ICMPv6 for normal operation
Conflicts with UFWtwo tools managing firewallchoose one control plane

Quick Reference

TaskCommand
List rulesetnft list ruleset
Apply confignft -f /etc/nftables.conf
Validate confignft -c -f /etc/nftables.conf
Enable servicesystemctl enable --now nftables
Add element to setnft add element inet filter ssh_allowlist { 203.0.113.99 }