nftables is the modern Linux firewall framework, replacing iptables. It provides a unified interface for IPv4, IPv6, ARP, and bridge filtering with improved performance and syntax.
Basic Commands
- nft list ruleset - List all rules
- nft list tables - List all tables
- nft list table <family> <name> - List specific table
- nft list chain <family> <table> <chain> - List specific chain
- nft flush ruleset - Clear all rules
- nft flush table <family> <name> - Clear specific table
- nft -s list ruleset - List with handle numbers
- nft monitor - Watch for rule changes in real-time
Address Families
- ip - IPv4 (default)
- ip6 - IPv6
- inet - IPv4 and IPv6 combined
- arp - ARP
- bridge - Bridge filtering
- netdev - Ingress filtering
Tables
Create Table
nft add table inet filter
nft add table ip nat
Delete Table
nft delete table inet filter
Chains
Chain Types
- filter - Packet filtering
- route - Rerouting packets
- nat - Network address translation
Chain Hooks
- prerouting - Before routing decision
- input - Incoming packets to local
- forward - Forwarded packets
- output - Outgoing packets from local
- postrouting - After routing decision
- ingress - Earliest hook (netdev only)
Create Chain
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
Delete Chain
nft delete chain inet filter input
Adding Rules
- nft add rule <family> <table> <chain> <rule> - Append rule
- nft insert rule <family> <table> <chain> <rule> - Insert at beginning
- nft add rule <family> <table> <chain> position <handle> <rule> - Add after handle
- nft delete rule <family> <table> <chain> handle <handle> - Delete by handle
Rule Matching
Interface Matching
- iifname "eth0" - Input interface name
- oifname "eth0" - Output interface name
- iif eth0 - Input interface (faster, index-based)
- oif eth0 - Output interface (faster, index-based)
Address Matching
- ip saddr 192.168.1.0/24 - Source IPv4 address
- ip daddr 10.0.0.1 - Destination IPv4 address
- ip6 saddr fe80::/10 - Source IPv6 address
- ip6 daddr ::1 - Destination IPv6 address
Protocol Matching
- ip protocol tcp - TCP protocol
- ip protocol udp - UDP protocol
- ip protocol icmp - ICMP protocol
- meta l4proto tcp - Layer 4 protocol (works with inet)
Port Matching
- tcp sport 22 - TCP source port
- tcp dport 80 - TCP destination port
- udp dport 53 - UDP destination port
- tcp dport { 22, 80, 443 } - Multiple ports
- tcp dport 1024-65535 - Port range
Verdicts (Actions)
- accept - Accept the packet
- drop - Drop silently
- reject - Reject with error
- queue - Send to userspace
- continue - Continue rule processing
- return - Return to calling chain
- jump <chain> - Jump to another chain
- goto <chain> - Go to chain without returning
Connection Tracking
- ct state new - New connections
- ct state established - Established connections
- ct state related - Related connections
- ct state invalid - Invalid packets
- ct state { established, related } - Multiple states
Common Examples
Allow SSH
nft add rule inet filter input tcp dport 22 accept
Allow Established Connections
nft add rule inet filter input ct state established,related accept
Block IP Address
nft add rule inet filter input ip saddr 192.168.1.100 drop
Allow HTTP/HTTPS
nft add rule inet filter input tcp dport { 80, 443 } accept
Allow Loopback
nft add rule inet filter input iifname "lo" accept
Log and Drop
nft add rule inet filter input log prefix "nftables-dropped: " drop
NAT Configuration
Masquerading (SNAT)
nft add table ip nat
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip nat postrouting oifname "eth0" masquerade
Port Forwarding (DNAT)
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add rule ip nat prerouting iifname "eth0" tcp dport 8080 dnat to 192.168.1.10:80
Complete Firewall Example
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Allow loopback
iifname "lo" accept
# Allow established/related
ct state established,related accept
# Drop invalid
ct state invalid drop
# Allow ICMP
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# Allow SSH
tcp dport 22 accept
# Allow HTTP/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;
}
}
Sets and Maps
Named Set
nft add set inet filter allowed_ips { type ipv4_addr \; }
nft add element inet filter allowed_ips { 192.168.1.1, 192.168.1.2 }
nft add rule inet filter input ip saddr @allowed_ips accept
Anonymous Set
nft add rule inet filter input ip saddr { 192.168.1.1, 192.168.1.2 } accept
Port Set
nft add set inet filter allowed_ports { type inet_service \; }
nft add element inet filter allowed_ports { 22, 80, 443 }
nft add rule inet filter input tcp dport @allowed_ports accept
Rate Limiting
# Limit to 10 packets per second
nft add rule inet filter input tcp dport 22 limit rate 10/second accept
# Limit with burst
nft add rule inet filter input tcp dport 22 limit rate over 10/second burst 5 packets drop
Saving and Loading
- nft list ruleset > /etc/nftables.conf - Save rules
- nft -f /etc/nftables.conf - Load rules from file
- systemctl enable nftables - Enable at boot
- systemctl start nftables - Start nftables service
Migration from iptables
- iptables-translate - Convert iptables rule to nft syntax
- iptables-restore-translate - Convert iptables-save output to nft
- iptables-nft - iptables compatibility layer using nftables backend
# Translate a single rule
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# Translate saved rules
iptables-save | iptables-restore-translate
Tips
- Use inet family for combined IPv4/IPv6 rules
- Use sets for multiple addresses or ports (more efficient)
- Use iifname/oifname for dynamic interfaces, iif/oif for static
- Chain priority determines order (lower = earlier)
- Use handles (-a flag) to identify rules for deletion
- nft monitor is useful for debugging rule changes
- Put rules in /etc/nftables.conf for persistence
- Use flush ruleset carefully - it removes everything
- Escape semicolons with backslash in shell commands
- nftables is the future - iptables is in maintenance mode