Migrating from iptables to nftables in 2026: a guide for Linux ops
If you're wondering how to migrate iptables to nftables in 2026, you're not alone—this transition is critical for modern Linux firewall management as iptables enters legacy maintenance mode. This guide walks you through the entire migration process, from understanding the fundamental architectural differences to executing a zero-downtime cutover, while addressing compatibility with Docker, fail2ban, and production XDP workloads like PAKKT.io.
The nftables framework has been the designated successor to iptables since kernel 3.13, offering a unified syntax for IPv4, IPv6, ARP, and bridge filtering within a single nft command-line tool. By 2026, most distributions ship nftables as the default, yet countless production servers still run iptables rulesets written a decade ago. Whether you manage game servers, API gateways, or database clusters, understanding this migration is no longer optional—it's a mandatory step to maintain security patching, leverage modern kernel features, and prepare for XDP/eBPF integration.
Why Migrate from iptables to nftables in 2026?
The iptables toolchain—comprising iptables, ip6tables, arptables, and ebtables—fragments filtering logic across multiple binaries and kernel subsystems. Each operates on separate tables (filter, nat, mangle, raw) with rigid hook priorities and verbose, repetitive syntax. nftables consolidates all these into a single nf_tables kernel API, reducing code duplication and enabling atomic rule updates.
From a performance perspective, nftables uses a virtual machine-like bytecode interpreter that processes ruleset expressions more efficiently than iptables' linear chain traversal. When combined with XDP programs—such as the single-program-per-interface architecture in PAKKT.io—you achieve a dual-layer defense: stateless sub-microsecond filtering at the driver level (XDP) and stateful connection tracking in nftables, all without the overhead of iptables-legacy compatibility shims.
Key Architectural Improvements
- Address family unification: A single
inetfamily handles both IPv4 and IPv6, eliminating duplicate rules. - Atomic ruleset replacement: Changes are staged in userspace and applied transactionally, preventing race conditions during reload.
- Native sets and maps: Store thousands of IPs, ports, or interface names in efficient hash or bitmap data structures, queried in O(1) time.
- Verdict maps: Jump to different chains based on packet metadata (e.g.,
meta mark,ct state) without cascading if-statements. - Simplified NAT: Port address translation no longer requires separate PREROUTING and POSTROUTING rules in multiple tables.
Security updates for iptables are increasingly backports-only; new netfilter features—such as flowtable offload, reject with ICMP policy, and BPF map integration—land exclusively in nftables. Organizations delaying migration face growing technical debt and miss optimizations critical for high-throughput workloads.

Pre-Migration Inventory and Compatibility Audit
Before touching any production firewall, document your current iptables state. Export every table to a text file for reference and rollback:
iptables-save > /root/iptables-backup-$(date +%F).rules
ip6tables-save > /root/ip6tables-backup-$(date +%F).rules
Parse these files to identify:
- Custom chains: Application-specific jump targets (e.g., DOCKER-USER, f2b-sshd).
- Third-party integrations: Rules inserted by fail2ban, Docker, Kubernetes kube-proxy, or VPN daemons.
- Stateful modules: Connection tracking helpers (nf_conntrack_ftp, nf_nat_pptp), which may need explicit nftables
ct helperobjects. - Rate-limiting: iptables
limitorhashlimitmodules, which translate to nftableslimitormeterstatements. - Packet mangling: DSCP marking, TTL modifications, or TCPMSS clamping in the mangle table.
Ensuring Zero-Conflict with Docker
Docker manipulates the iptables nat and filter tables to implement container networking. The daemon watches for iptables changes and reinjects its rules, which can interfere with manual migrations. The safest approach is to create an isolated nftables table (e.g., inet pakkt) that Docker never touches. PAKKT.io uses exactly this pattern: all XDP-driven rules and nftables policies reside in a dedicated inet pakkt table with priority 0, while Docker continues managing iptables in parallel until you fully decommission the legacy stack.
Verify Docker's iptables backend:
docker info | grep -i iptables
If the output shows iptables: true, Docker will not interfere with nftables tables. If your distribution uses the iptables-nft compatibility layer (Debian 11+, Ubuntu 20.04+), both iptables commands and nft commands share the same kernel nf_tables backend, so Docker's insertions appear as nftables rules but remain logically separate.
fail2ban and Dynamic Blacklists
fail2ban's default action files call iptables to ban IPs. Switch to nftables actions by editing /etc/fail2ban/jail.local:
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports
Create a dedicated nftables set for banned IPs:
nft add table inet f2b
nft add set inet f2b banned { type ipv4_addr\; flags timeout\; }
nft add chain inet f2b input { type filter hook input priority 0\; }
nft add rule inet f2b input ip saddr @banned drop
Update fail2ban action files to use nft add element inet f2b banned { $IP timeout 1h }. This method is conceptually identical to PAKKT's dual-layer IP blacklist: XDP BPF map for line-rate drops, and an nftables set for stateful tracking—automatically synchronized via the agent's 30-second heartbeat.

Step-by-Step Migration Procedure
This procedure assumes a single-server environment running a kernel ≥5.x (required for robust XDP and nftables flowtable support). Adjust hook priorities if you integrate with existing nftables policies.
1. Install nftables and Translation Tools
apt update && apt install -y nftables iptables-nft-compat
systemctl enable nftables
systemctl start nftables
Verify the nft binary:
nft --version
Expected output: nftables v1.0.x or higher.
2. Translate Existing iptables Rules
Use the iptables-restore-translate utility, which parses iptables-save output and emits approximate nftables syntax:
iptables-save | iptables-restore-translate -f /dev/stdin > /etc/nftables.conf.draft
Review /etc/nftables.conf.draft carefully. The auto-translation is not perfect:
- Chain priorities: iptables hooks map to nftables priorities (filter input = priority 0, nat prerouting = priority -100). Confirm no collisions.
- Jump targets: Custom chains are preserved, but ensure they reference the correct address family (inet, ip, ip6).
- Match extensions: Some iptables modules (e.g.,
-m u32) have no nftables equivalent; rewrite using raw payload expressions. - Logging:
-j LOGbecomeslog prefix "...", but syslog configuration must routekern.warningto the desired file.
3. Create an Isolated Table for New Policies
Rather than replacing the entire iptables ruleset in one transaction, deploy new rules in a separate nftables table. This pattern mirrors the PAKKT Integrations design:
nft add table inet pakkt
nft add chain inet pakkt input { type filter hook input priority 0\; policy accept\; }
nft add chain inet pakkt forward { type filter hook forward priority 0\; policy accept\; }
Priority 0 ensures the pakkt table evaluates at the same stage as iptables filter hooks. If you already have another nftables table at priority 0, shift pakkt to priority 1 to layer policies.
4. Port Essential Rules
Start with SSH, established connections, and ICMP:
nft add rule inet pakkt input iif lo accept
nft add rule inet pakkt input ct state established,related accept
nft add rule inet pakkt input tcp dport 22 ct state new limit rate 5/minute accept
nft add rule inet pakkt input icmp type echo-request limit rate 10/second accept
nft add rule inet pakkt input icmpv6 type { echo-request, nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
For game servers or API endpoints, add port-specific rules with stateful rate-limiting:
nft add rule inet pakkt input tcp dport 25565 ct state new limit rate 50/second accept comment "Minecraft new connections"
nft add rule inet pakkt input udp dport 27015 meter udp_flood { ip saddr limit rate 100/second } accept comment "Source Engine query rate-limit"
The meter statement creates a dynamic per-source-IP counter, equivalent to iptables hashlimit but with cleaner syntax.
5. Configure Connection Tracking Helpers
If your old iptables ruleset loads connection tracking helpers (FTP, SIP, PPTP), define them explicitly in nftables:
nft add ct helper ftp-standard { type "ftp" protocol tcp\; }
nft add rule inet pakkt prerouting tcp dport 21 ct helper set "ftp-standard"
Verify active helpers:
cat /proc/net/nf_conntrack_expect
6. Test in Parallel with iptables
At this stage, both iptables and nftables are active. Packets traverse iptables hooks first (legacy Netfilter), then nftables hooks. Monitor counters:
nft list ruleset -a
The -a flag displays handle IDs and packet/byte counters. Compare these to iptables -nvL to confirm traffic is hitting the new rules. If counters remain zero, check hook priority order and policy (accept vs. drop).
7. Disable iptables Services
Once confident, flush iptables rules and disable persistence services:
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
ip6tables -F
ip6tables -X
systemctl disable iptables
systemctl disable ip6tables
systemctl disable netfilter-persistent
On Debian/Ubuntu, remove the iptables-persistent package if installed:
apt remove --purge iptables-persistent
Reboot to confirm the nftables ruleset loads from /etc/nftables.conf and no iptables rules reappear.
8. Integrate XDP for Line-Rate Pre-Filtering
With nftables handling stateful filtering, offload high-volume, stateless drops to XDP. PAKKT.io deploys a single XDP program per interface (pakkt_engine.bpf.o) that consults up to 256 rules stored in BPF maps. Each rule specifies port range, protocol, action (XDP_DROP, XDP_PASS), and per-port packet-per-second limits. Because XDP runs before the kernel allocates an skb, it drops attack traffic with negligible CPU cost—several million packets per second on commodity 10GbE NICs.
Manual XDP attachment example:
ip link set dev eth0 xdp obj pakkt_engine.bpf.o sec xdp
bpftool map dump name pakkt_rules
PAKKT automates this via the lightweight Go agent, which receives rule updates over mTLS, updates BPF maps atomically, and synchronizes blacklist/whitelist entries between XDP and nftables every 30 seconds. The agent's footprint is <1% CPU and <5 MB RAM, ensuring zero impact on game server tick rates or database query latency.
Advanced nftables Features for Production Workloads
Once basic connectivity is stable, leverage nftables capabilities that have no iptables equivalent.
Flowtable Offload for Established Connections
Flowtable offload bypasses the full netfilter stack for established flows, handing them directly to the NIC or a software fast-path. This reduces per-packet CPU cycles for long-lived connections (e.g., game sessions, database replication).
nft add flowtable inet pakkt fastpath { hook ingress priority 0\; devices = { eth0 }\; }
nft add rule inet pakkt forward ct state established flow add @fastpath
Monitor offloaded flows:
cat /proc/net/nf_flowtable
Flowtable offload is most effective on kernels ≥5.10 with hardware that supports TC_SETUP_FT (e.g., Mellanox ConnectX, Intel E810).
Named Sets for Dynamic Blacklists
Create IPv4 and IPv6 sets with automatic timeout, populated via API or agent:
nft add set inet pakkt blacklist_v4 { type ipv4_addr\; flags timeout\; }
nft add set inet pakkt blacklist_v6 { type ipv6_addr\; flags timeout\; }
nft add rule inet pakkt input ip saddr @blacklist_v4 drop
nft add rule inet pakkt input ip6 saddr @blacklist_v6 drop
Add an IP with a 1-hour timeout:
nft add element inet pakkt blacklist_v4 { 203.0.113.42 timeout 1h }
This architecture is foundational to PAKKT's dual-layer blacklist: the XDP BPF map drops packets at line rate, and the nftables set provides stateful logging and integration with intrusion detection systems.
Verdict Maps for Policy Routing
Route packets to different chains based on interface or conntrack mark:
nft add chain inet pakkt input_dispatch
nft add rule inet pakkt input_dispatch meta iifname vmap { "eth0" : jump wan_rules, "eth1" : jump lan_rules }
This eliminates long if-else chains and improves ruleset readability.
Per-Connection Rate-Limiting with Meters
Limit new connections per source IP, per destination port:
nft add rule inet pakkt input tcp dport 3306 meter mysql_connlimit { ip saddr ct count over 10 } reject with tcp reset
The ct count expression tracks active connections from each source. This prevents connection exhaustion attacks against MySQL, PostgreSQL, or game server query ports.
Post-Migration Validation and Monitoring
Migration is complete when your server has been rebooted multiple times, all services are reachable, and no iptables rules persist. Validate with:
iptables -nvL
ip6tables -nvL
nft list ruleset
The first two commands should return empty or default-policy-only chains. The third should display your production nftables configuration.
Integrate with Centralized Logging
Configure nftables to log rate-limited or dropped packets:
nft add rule inet pakkt input limit rate 10/minute log prefix "PAKKT-DROP: " drop
Route these logs to a dedicated file via rsyslog:
:msg, contains, "PAKKT-DROP" -/var/log/pakkt-firewall.log
& stop
PAKKT's centralized panel aggregates these logs alongside XDP drop counters, GeoIP metadata, and per-port metrics stored in TimescaleDB. The real-time dashboard visualizes attack patterns on a world map, highlighting top source IPs and countries—essential for correlating DDoS campaigns across multiple agents.
Performance Regression Testing
Benchmark packet throughput before and after migration using iperf3 (TCP) and hping3 (UDP flood):
iperf3 -s -p 5201
# From client:
iperf3 -c SERVER_IP -p 5201 -t 60 -P 10
For UDP packet rate:
hping3 --udp -p 27015 --flood SERVER_IP
Monitor CPU usage with top or htop. Well-tuned nftables rulesets should show comparable or lower ksoftirqd CPU than iptables. When XDP is active, expect dramatic reductions—attack packets never reach the network stack.
Audit for Rule Redundancy
nftables syntax is expressive, but redundant rules still hurt performance. Use nft list ruleset -a to identify handle IDs, then delete obsolete entries:
nft delete rule inet pakkt input handle 42
Consolidate similar rules with sets:
nft add set inet pakkt game_ports { type inet_service\; elements = { 25565, 27015, 7777 } \; }
nft add rule inet pakkt input tcp dport @game_ports ct state new limit rate 50/second accept
This replaces three separate rules with one, reducing evaluation overhead.
Conclusion
Migrating from iptables to nftables in 2026 is a necessary evolution for any Linux-based infrastructure. By following this structured approach—inventory, translation, isolated table deployment, parallel testing, and XDP integration—you achieve a robust, maintainable firewall that scales with modern kernel capabilities. The dual-layer defense of stateless XDP filtering and stateful nftables policies, as implemented by platforms like PAKKT.io, ensures both line-rate drop performance and fine-grained connection tracking without conflict with Docker, fail2ban, or existing network automation.
FAQ
Can I run iptables and nftables simultaneously during migration?
Yes, both frameworks can coexist because they share the same Netfilter hooks in the kernel. Packets will traverse iptables rules first, then nftables rules. However, to avoid confusion and double-processing overhead, deploy new policies in an isolated nftables table (e.g., inet pakkt) and flush iptables only after validating that the nftables ruleset handles all traffic correctly.
Do nftables meters consume more memory than iptables hashlimit?
No—nftables meters use the same underlying kernel hash table structures as iptables hashlimit, but expose a cleaner syntax. Memory usage depends on the number of unique tracked keys (source IPs, destination ports) and timeout values, not the framework. For very large sets (millions of entries), consider offloading stateless drops to XDP with BPF maps, which scale more efficiently than either nftables or iptables.
How do I ensure XDP and nftables blacklists stay synchronized?
Manual synchronization requires updating both the XDP BPF map (via bpftool map update) and the nftables set (via nft add element) every time you ban or unban an IP. This is error-prone at scale. Platforms like PAKKT.io solve this with a lightweight agent that receives centralized blacklist updates over mTLS and atomically applies them to both layers every 30 seconds, ensuring consistent policy enforcement with zero manual intervention.
Deploy PAKKT in 30 seconds
Dual-layer kernel protection. XDP + nftables. Driven from a central panel. 7-day free trial.