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)
This page focuses on understanding how nftables works, reading and writing common rules, and building safe baseline firewall configurations for servers.
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:
| Family | Description |
|---|---|
| -- | -- |
inet | Works for both IPv4 and IPv6 (recommended for most servers) |
ip | IPv4 only |
ip6 | IPv6 only |
arp | ARP rules (rare for typical VPS hardening) |
bridge | Bridged traffic |
Chains
Chains attach to Netfilter hooks. Common hooks:
| Hook | Typical Use |
|---|---|
input | Traffic destined to the local host |
output | Traffic originating from the local host |
forward | Traffic 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:
acceptdroprejectlogjump <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 -Sshows 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.confunless you fully control the design and understand the interaction
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
| Symptom | Likely Cause | Fix |
|---|---|---|
| -- | - | |
| Locked out over SSH | SSH not allowed before policy drop | Add SSH allow first; use console recovery |
| Rules not persistent after reboot | nftables service not enabled or config not used | enable service; verify /etc/nftables.conf |
| ICMP blocked (network issues) | ICMP rules missing | allow ICMP/ICMPv6 for normal operation |
| Conflicts with UFW | two tools managing firewall | choose one control plane |
Quick Reference
| Task | Command |
|---|---|
| List ruleset | nft list ruleset |
| Apply config | nft -f /etc/nftables.conf |
| Validate config | nft -c -f /etc/nftables.conf |
| Enable service | systemctl enable --now nftables |
| Add element to set | nft add element inet filter ssh_allowlist { 203.0.113.99 } |