Tutorials nftables — The Must-Use iptables Successor for Modern Gateway Servers Written by Adam Muiz 12 Jun 2026 Updated: 06 Aug 2026 10 min read In the article server as router, I mentioned nftables as firewall and NAT backbone. In the article DNS poisoning, I will give an example of nftables rules for redirecting port 53 and blocking DoH. But it feels like these two articles haven't given nftables the platform it deserves — even though this is the tool that I think is the most powerful in the Linux networking ecosystem today. This article will be a practical guide to nftables from a gateway server perspective — not just theory, but the rules I actually use everyday on a home server. For those who have read the previous two articles, this is the missing piece that ties it all together. Why nftables, not iptables? iptables has accompanied Linux administrators for more than 20 years. But it hasthree fundamental weaknesses that make it a pain to use on a modern scale: Linear processing — each packet is checked rule by rule sequentially. In iptables, if you have 100 rules in the FORWARD chain, the package must tested 100 times before getting to the final rule. nftables uses set hashing and maps which makes lookups O(1) — constant, no matter 10 or 10,000 rules.Two separate tools — iptables for IPv4, ip6tables for IPv6, arptables for ARP, ebtables for bridge. Each has a different syntax. nftables handles it all in one tool: nft.Verbose and error-prone syntax — iptables requires flags like -A, -I, -s, -d, --dport whose sequence is rigid. nftables has a more declarative and consistent syntax. But the advantage of nftables that I feel the most is atomic rule replacement. In iptables, if you want to clear all the rules and start from Initially, they have to be flushed one by one — and during that flush process, the firewall is in an empty (unsafe) state. nftables can update the entire ruleset in one operation atomic uses nft -f ruleset.nft. There is no gap where the firewall has no rules. Basic Concepts of nftables Before getting into the rules of thumb, it's important to understand nftables' three hierarchical levels: Tables — container for chains. Each table has a family (ip, ip6, inet, arp, bridge, netdev). For the gateway server, we can just use it inet which handles IPv4 and IPv6 at once.Chains — sequence of rules. There are base chains (hooks tied: prerouting, input, forward, output, postrouting) and regular chains (a call from another rule, such as a function call).Rules — contains expressions (conditions) and verdicts (actions: accept, drop, reject, jump, goto, return, continue). This is an example of a minimal table and chain for a gateway: table inet gateway { chain input { type filter hook input priority 0; policy drop; ct state established,related accept iif lo accept tcp dport {22, 80, 443} accept } chain forward { type filter hook forward priority 0; policy drop; ip saddr 192.168.1.0/24 accept } chain postrouting { type nat hook postrouting priority 100; policy accept; oif eth0 masquerade } } Note: policy drop in input and forward chains. This defaults to deny — only explicitly allowed traffic can pass. Security principles the most fundamental which unfortunately is rarely implemented in home routers. 1. NAT Masquerade — The Heart of the Gateway Server In the server as router article, this is the most important rule. Without this, devices on the local network cannot access the internet because the server does not forward packets them to the internet. table inet nat { chain postrouting { type nat hook postrouting priority srcnat; policy accept; oifname "eth0" masquerade } } masquerade automatically replaces the source address of every packet that goes out via eth0 with the server IP. When the response returns, nftables returns the device's original address on the local network. All devices behind the server can surf the internet without additional configuration. Compare with iptables: # iptables — verbose, dua aturan terpisah untuk IPv4 dan IPv6 iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE nftables handles IPv4 and IPv6 in one line with the inet family. Cleaner, less things can go wrong. 2. Port Forwarding — Access Services from Outside Sometimes we want services on the local network to be accessible from the internet — for example a web server at IP 192.168.1.10:80. In nftables, this is called adestination NAT(dstnat) and done in chain prerouting: table inet nat { chain prerouting { type nat hook prerouting priority dstnat; policy accept; tcp dport 80 dnat to 192.168.1.10:80 tcp dport 443 dnat to 192.168.1.10:443 } chain forward { type filter hook forward priority 0; policy drop; # Izinkan traffic ke server internal tcp dport {80, 443} ip daddr 192.168.1.10 ct state new accept } } Note: apart from dnat prerouting, we also need rules in the forward chain to allow traffic to the internal IP. Many do forgot this and wondered why port forwarding wasn't working — even though the packet had been NATed, it was dropped by chain forward. 3. DNS Control — Redirect and Block DoH This is the rule I covered in the DNS poisoning article — how to force all devices on a network to use a local DNS server: table inet dns-control { chain prerouting { type nat hook prerouting priority -100; policy accept; # Redirect semua DNS ke DNSMasq lokal (192.168.1.2) udp dport 53 dnat to 192.168.1.2:53 tcp dport 53 dnat to 192.168.1.2:53 } chain forward { type filter hook forward priority 0; policy accept; # Blokir DoH ke provider publik tcp dport 443 ip daddr {1.1.1.0/24, 8.8.8.0/24, 9.9.9.0/24} drop } } The difference with the version in the DNS poisoning article: here I use set literal {1.1.1.0/24, 8.8.8.0/24, 9.9.9.0/24}. nftables change this set becomes a hash table in the kernel — O(1) lookup, no matter how many IPs are in the set. In iptables, each IP needs a separate rule checked one by one. 4. Bandwidth Limiting per Device — Interval and Burst One of the features I like most about the gateway server is that it can limit bandwidth per device. In nftables, this is done with meters or quotas: table inet bandwidth { chain forward { type filter hook forward priority 0; policy accept; # Batasi device 192.168.1.50 maksimal 10MB per 6 jam ip saddr 192.168.1.50 quota over 10 mbytes until 6h drop ip saddr 192.168.1.51 quota over 50 mbytes until 12h drop } } The rules above will track the amount of data sent by a particular device. When the quota is exceeded, the next package will be dropped until the quota reset period. Very useful for digital boundaries — give your child 10MB of internet per 6 hours, after that you have to wait for a reset. But this is a simple quota. For rate limiting (limiting speed, not amount), nftables has limit: # Batasi kecepatan download device: maksimal 1MB/s dengan burst 2MB ip saddr 192.168.1.50 limit rate 1 mbytes/second burst 2 mbytes accept ip saddr 192.168.1.50 drop The first rule allows packages as long as they are within the rate limit. The second rule drops packets that exceed the limit. The effect: the device has maximum downloads 1MB/s, with 2MB burst to compensate for fluctuations. 5. Connection Tracking — Allow Existing Connections to Run The rule that beginners most often forget is connection tracking. Without this, every packet in a single TCP connection would have to pass through all the rules firewall — inefficient. chain forward { type filter hook forward priority 0; policy drop; # Izinkan koneksi yang sudah established ct state established,related accept # Hanya koneksi baru yang diperiksa ct state invalid drop ip saddr 192.168.1.0/24 accept } The ct state established,related accept rule is on the first line. That is, after the initial connection is allowed, subsequent packets in the same connection (including reply packets from the internet) are immediately accepted without being checked again. This saves CPU and speeds up throughput significantly significant. 6. Logging — Seeing What Cannot Be Seen nftables has an integrated logging feature — not just accept/drop logs, but can log detailed packet metadata: chain forward { type filter hook forward priority 0; policy drop; ct state established,related accept # Log semua koneksi baru yang mencoba keluar ip saddr 192.168.1.0/24 ct state new log prefix "FWD:NEW: " accept # Log paket aneh yang di-drop log prefix "FWD:DROP: " drop } With log prefix, each log line can have its origin identified. In /var/log/kern.log, an entry will appear like: kernel: FWD:NEW: IN=eth1 OUT=eth0 SRC=192.168.1.50 DST=203.0.113.5 PROTO=TCP SPT=45123 DPT=443 For gateway servers, these logs are very useful for: Detect devices that try to access suspicious domains/IPsVerify that firewall rules work as expectedDebugging a connection that can't get to the internet — is it a firewall drop or another problem? 7. Advanced: Named Sets for Easy Management This is the feature that makes nftables truly superior to iptables: named sets. Instead of writing IPs one by one in the rules, we create sets can be filled/emptied without needing to reload the entire ruleset: table inet filter { set blocked-ips { type ipv4_addr flags interval auto-merge } set blocked-domains { type ipv4_addr flags interval } chain forward { type filter hook forward priority 0; policy accept; ip saddr @blocked-ips drop ip daddr @blocked-domains drop } } # Isi set (bisa kapan saja, tanpa reload) nft add element inet filter blocked-ips { 192.168.1.50, 192.168.1.51 } nft add element inet filter blocked-domains { 203.0.113.0/24 } The advantage: we can add/remove IPs from the set with one command nft add element or nft delete element. No need rewrite the entire ruleset. Very suitable for integration with monitoring dashboards like the one I discussed in the server article as a router — just one endpoint API that calls nft add element to block devices from the dashboard. 8. Advanced: Maps for Selective Routing Maps in nftables allow us to perform different actions based on conditions — a kind of switch-case in the kernel: table inet nat { map port-forward { type inet_service : dnat_addr elements = { 80 : 192.168.1.10, 443 : 192.168.1.10, 22 : 192.168.1.20, 32400 : 192.168.1.30, } } chain prerouting { type nat hook prerouting priority dstnat; policy accept; tcp dport vmap @port-forward dnat to :tcp dport } } This map defines which ports are directed to which IPs. When there is a connection to port 80, nftables immediately looks up to map and dnat to the appropriate IP — O(1), without the need for nested rules. Want to add port forwarding? Just add elements to the map. Want to delete it? Just delete the element. No need to touch the main rules. Performance: nftables vs iptables in the Real World I once ran a simple test on the same server — Debian 12, kernel 6.1, Intel Celeron N3350 CPU. With 50 IP blocking rules in iptables, throughput down from 940 Mbps to around 720 Mbps. With the same rules in nftables using set, throughput remains at 930+ Mbps. The cause: iptables checks each rule linearly. Each package must pass 50 rules. nftables with a hash set simply performs one lookup — O(1). The more rules, the bigger the difference. On a home gateway server with a bandwidth of 100-500 Mbps, this difference may not be felt. But for those who have gigabit connections or thousands of blocking rules, the difference is very significant. Conclusion nftables isn't just a replacement for iptables — it's a conceptual leap in how we manage firewalls on Linux. With syntax Cleaner, better performance, and features like named sets, maps, and quotas, nftables provides complete control over network traffic with a way that was previously impossible to do with iptables without a complicated script. If you have read the article server as router and DNS poisoning, now you have one more weapon in your arsenal: nftables as muscle that executes firewall, NAT, and filtering rules at speed kernel-native. DNSMasq is the brain that determines where a domain should be directed. And nftables as a hand that ensures only traffic the legitimate one can pass. The combination of DNSMasq + nftables + gateway server is the foundation of a home networking infrastructure that is powerful, cheap, and — most importantly — you who is in full control. For complete reference, man nft in the terminal is your best friend. Or visit wiki.nftables.org for official documentation.