What is nftables and the Core Reasons for Migrating from iptables
The Linux kernel's netfilter subsystem has provided packet classification and filtering functionality through iptables for many years. However, nftables stands as the new user-space tool (nft) and data model for netfilter; it manages IPv4, IPv6, ARP, and bridge traffic within the same table using a single command set. This unified structure reduces rule duplication and provides lower memory consumption compared to iptables in terms of performance.
Docker allows you to directly prefer nftables using the --firewall-backend=nftables option (Docker Docs).
Docker and nftables Integration
Docker's nftables integration can be enabled in two ways:
- Command line:
dockerd --firewall-backend=nftables
-
Daemon configuration file (
/etc/docker/daemon.json):
{
"firewall-backend": "nftables"
}
After applying these settings, you need to restart the Docker service:
sudo systemctl restart docker
When Docker restarts, you can see a table named docker created in the nft list ruleset output:
# nft list ruleset
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
}
}
table ip nat {
chain POSTROUTING {
type nat hook postrouting priority 100; policy accept;
}
}
table ip docker {
chain DOCKER-USER {
type filter hook prerouting priority -300; policy accept;
}
}
This example shows that Docker manages its own bridge and NAT rules over nftables. To ensure that iptables-based rules are no longer present on the system, you can check the iptables -L command; an empty output indicates a successful migration.
Creating Basic nftables Rules
Creating a filter table and an input chain with nftables is a common starting step:
sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0\; policy drop\; }
Here, policy drop is the default action; then we define the trusted traffic:
sudo nft add rule inet filter input iif "lo" accept
sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input ip protocol icmp accept
These three lines accept loopback, established connections, and ICMP (like ping) packets. All remaining traffic is rejected due to the default drop policy. The rule list can be displayed as follows:
# nft list chain inet filter input
chain input {
type filter hook input priority 0; policy drop;
iif "lo" accept
ct state established, related accept
ip protocol icmp accept
}
This structure offers a minimal firewall and new service ports can be added as needed.
Converting Existing iptables Rules to nftables
A method similar to iptables-restore is available to translate iptables rules directly into the nft command. Docker documentation recommends a migration that provides the same functionality using nft commands instead of iptables-legacy. An example iptables rule:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
Translating this rule to nftables:
sudo nft add rule inet filter input tcp dport 22 accept
During conversion, rule order is important; the insertion order within the nftables chain can be controlled with the position parameter (e.g., position 1). However, direct intervention in chains automatically created by Docker (DOCKER-USER, DOCKER-INGRESS) is not recommended; instead, adding additional rules to the DOCKER-USER chain is a safer approach:
sudo nft add rule inet docker DOCKER-USER ip saddr 192.168.0.0/16 drop
This example blocks a specific IP block from accessing Docker containers and does not conflict with Docker's own chains.
Verification, Testing, and Rollback Strategies
Post-migration verification should be done in two phases:
-
Rule list check – Ensure the
nft list rulesetoutput contains the expected tables and chains. -
Live traffic test – Check specific ports using tools like
curlornc. For example, testing SSH (port 22) access:
nc -zv 127.0.0.1 22
A successful connection yields the message Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!; this message indicates there is no blocking in Docker's DOCKER-USER chain.
The rollback scenario is performed by saving the nftables configuration to an old file and restoring it with the nft -f command:
sudo nft list ruleset > /etc/nftables.backup
# ... changes ...
# If a problem occurs:
sudo nft -f /etc/nftables.backup
This method ensures an atomic rollback; because nftables reloads the rules file completely, no inconsistency occurs in intermediate states. The same approach applies to Docker; when you revert the daemon.json file and restart the Docker service, Docker automatically rolls back to iptables-based rules.
Performance and Scalability Analysis
The single-table approach of nftables keeps memory usage low even as the number of rules increases in large-scale environments. The Ubuntu Security Documentation states that nftables uses a BPF-based engine directly within the netfilter kernel during the packet classification process; this completes the rule matching time with fewer CPU cycles compared to iptables. We cannot give exact numbers without a real measurement report, but at high connection density (e.g., 10 Gbit/s NIC), it has been observed that the latency increase of nftables generally remains in the millisecond range.
This performance advantage is a critical factor for container-orchestrated environments (Kubernetes, Docker Swarm); while the iptables chain can bloat rapidly when every pod/service adds a firewall rule, nftables keeps these rules within a single table.
Security and the Zero-Trust Approach
Zero-Trust architecture requires every packet to go through authentication and authorization checks. Nftables makes it possible to fine-tune this control with its packet-mark and conntrack features. For example, you can mark a packet and check this mark later in another chain:
sudo nft add rule inet filter prerouting ip daddr 10.0.0.0/8 meta mark set 0x1
sudo nft add rule inet filter input meta mark 0x1 accept
These two steps pre-mark packets routed to a specific destination network and accept only marked packets; all other packets are rejected by the default drop policy. Such a structure provides a fundamental block for segmentation and micro-perimeter applications.
Mermaid Diagram: nftables Traffic Flow
This diagram visualizes how incoming packets are evaluated in the nftables chain and how the accept or drop decision directs them to the next step.
Packet Processing Hierarchy and Methods of nftables
Nftables offers a hierarchy based on the concept of hooks, which determine in which chain packets will be processed. Multiple chains can be created within each table (e.g., inet, ip, ip6, arp, bridge), and these chains run in the order of prerouting → input → forward → output → postrouting. For example, an incoming packet is first inspected in the prerouting chain and then directed to the input chain; this sequence ensures that packet filtering and NAT processes are performed at the correct place in the network layer.
The packet classification process is carried out using conntrack, meta, and bpf fields. The nft commands use a BPF-based compiler to match packets quickly; this reduces the number of CPU cycles during the inspection of each packet compared to iptables. For example, a rule like ct state established,related queries the connection tracking table and accepts only the continuation of existing connections. Thus, even with millions of simultaneous connections, the memory and processor cost remains low.
This structure offers the flexibility to manage all protocols within a single table; however, the learning curve can be steep. Users must understand the hook order and chain types well to reduce the risk of misconfiguration. Additionally, when creating complex rule sets, one must be aware of the rule order concept; the priority of the added rule can be controlled with the position parameter.
Dynamic Rule Management with nftables in Docker Swarm and Kubernetes
Orchestration platforms dynamically add new rules per pod or service. Nftables can perform these updates in real-time with the nft command. For example, when a new service is started in Swarm, we can open the relevant port with the following command:
sudo nft add rule inet filter forward tcp dport 8080 ct state new accept
This command adds a new rule to the forward chain in the filter table to accept new connections coming to port 8080. When the same command is run with a CNI plugin in a Kubernetes environment, a separate rule can be created for each pod. For example, when using the cni-nftables plugin instead of kube-proxy, service IPs are added directly to the nftables table and network policies are applied through this table.
Dynamic rule management provides a huge advantage in terms of scalability: when a new pod or service is added, the necessary rules are automatically added, eliminating the need for manual intervention. However, it requires plugin support; some older CNI plugins may not be fully compatible with nftables. Also, if a large number of rules are added quickly, the table size can increase, which can affect memory usage, so it is important to review the rule set regularly.
Logging and Monitoring Integration with nftables
Nftables can log packets directly to system logs thanks to the log target. A simple example is sending all incoming packets for a specific port to syslog:
sudo nft add rule inet filter input tcp dport 22 log prefix "SSH attempt: " level notice
This rule writes every incoming TCP packet on port 22 to syslog at the notice level. To inspect the logs, you can check journalctl -u nftables or the syslog files. For more advanced monitoring, you can observe the live packet stream with the nft -i interactive mode or the nft monitor command. For example:
sudo nft monitor
This command shows all nftables events in the system in real-time. Additionally, you can route packets to user space using the nfqueue target and develop a custom monitoring application:
sudo nft add rule inet filter input udp dport 53 nfqueue num 0
This way, DNS traffic is transferred to user space and detailed analysis can be performed.
Although logging is critical for system security, generating excessive logs can increase CPU and disk usage. Therefore, limiting logging rules (e.g., for specific IP ranges) and lowering the log level (e.g., warning instead of info) reduces the impact on performance. At the same time, rotating and archiving logs at regular intervals prevents disk space issues.
Conclusion
In this guide, we presented a comprehensive migration path from Docker's nftables-based firewall integration to basic rule creation, iptables-to-nftables conversion, verification, and rollback processes. The single-table architecture of nftables offers clear advantages over iptables in terms of performance and ease of management; it also provides fine-tuning options compatible with Zero-Trust principles. When implementing the migration, carefully monitor the daemon.json setting and nft commands, and do not forget to take a backup before making changes. When you need to, you can roll back instantly with nft -f /etc/nftables.backup to guarantee the uninterrupted operation of your system.
Next step: Inspect container traffic at a central point by adding service ports specific to your environment to the DOCKER-USER chain.
Official Sources
- Docker with nftables | Docker Docs
- Migrate firewall to use direct nftables rules (currently using…
- nftables - Ubuntu security documentation
- Transparent proxy support — The Linux Kernel documentation
- nftables - ArchWiki
- systemd-devel HEADSUP nspawn/networkd: moving from iptables...
- Minimal requirements to compile the Kernel — The Linux Kernel…
- GitHub - google/nftables: This repository contains a Go module to ...
Top comments (0)