Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

nftables: The Modern Linux Firewall

By Kokil Thapa | Last reviewed: September 2026

nftables: The Modern Linux Firewall is the default packet-filtering stack on current Ubuntu and Debian releases. It replaces the fragmented iptables, ip6tables, arptables, and ebtables front ends with one nft binary and one kernel ruleset. If you maintain Laravel apps, WordPress shops, or API servers on Ubuntu, you still need a host firewall beneath UFW or beside it. I've hardened dozens of production boxes with Linux system administration work, and nftables is what I reach for when UFW's abstraction gets in the way.

What is nftables and why did Linux replace iptables?

Netfilter has always lived inside the Linux kernel. For years, userspace tools split that power across multiple binaries. Each tool compiled rules differently. IPv4 and IPv6 needed separate files. Atomic updates were painful.

nftables fixes that with a single virtual machine for rule expressions. You write human-readable rules. The kernel executes them efficiently. Sets, maps, and intervals are first-class. Dynamic sets even accept element updates without reloading the entire ruleset.

On Ubuntu 22.04 and 24.04, nftables is the backend UFW can delegate to. You can run UFW for simple cases and drop to raw nft when you need named sets, rate limiting, or custom NAT. That split matches how I operate on sister legal-tech sites sharing one EC2 host.

nftables: The Modern Linux Firewall StackLegacy iptables eraiptablesip6tablesarptablesebtablesSeparate rule filesxtables kernel ABInftables eranft CLISingle rulesetNetfilter engine
nftables: The Modern Linux Firewall consolidates four legacy tools into one nft binary talking to Netfilter.

The official nftables wiki documents the full expression grammar. For day-to-day server work, you need tables, chains, rules, and sets—not every advanced match type.

Featureiptables (legacy)nftables
IPv4 + IPv6Separate binaries and filesOne nft ruleset
Rule updateRow-by-row, non-atomicAtomic full-table replace
IP listsipset (extra tool)Native sets and maps
SyntaxReverse-polish, terse flagsStructured, readable blocks
PerformanceGoodBetter with large rule sets
Ubuntu 24.04 defaultCompatibility layer onlyPrimary backend

See the side-by-side breakdown in our iptables vs nftables comparison if you are deciding when to migrate.

How do you install and enable nftables on Ubuntu?

Installation is straightforward on Ubuntu 22.04 and 24.04. The package ships a systemd unit and a skeleton config. Follow this sequence on a fresh VPS before exposing SSH to the public internet.

  1. Install the package and inspect the default config path.
  2. Define a minimal ruleset that keeps SSH open.
  3. Enable the systemd unit so rules survive reboot.
  4. Verify with nft list ruleset before closing your current session.

Install packages

sudo apt update
sudo apt install nftables
sudo systemctl enable nftables

Confirm the kernel module is available:

lsmod | grep nf_tables
sudo nft list tables

Minimal /etc/nftables.conf

Start with a deny-by-default inbound policy on the filter table. Allow established traffic, loopback, and SSH. This mirrors what UFW on Ubuntu does, but you control every line.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        ct state established,related accept
        iif "lo" accept
        tcp dport 22 accept
        tcp dport { 80, 443 } accept
        icmp type echo-request accept
        icmpv6 type { echo-request, nd-neighbor-solicit, nd-router-advert } accept
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Load and persist:

sudo nft -f /etc/nftables.conf
sudo systemctl restart nftables
sudo systemctl status nftables

Keep a second SSH session open while testing. Locking yourself out is the oldest firewall mistake. I have recovered servers remotely after bad iptables rule ordering; nftables does not forgive a missing port 22 either.

nftables Rule Evaluation FlowIncoming packetHook: prerouting / inputMatch: addr, port, setVerdict: accept / dropAcceptDropChain policy if no match
Each packet traverses hooks, matches expressions, and receives a verdict before the chain policy applies.

How do you write nftables rules for a production web server?

A typical stack runs Apache or Nginx with PHP-FPM 8.3 or 8.4, MySQL 9.7 or MariaDB 12.3 on localhost, and Redis 8.10 for cache. The firewall should expose 80 and 443, rate-limit SSH, block bogons, and refuse direct database ports from the internet.

Sets for blocklists and allowlists

Named sets keep rules readable. Add abusive IPs at runtime without editing the main config file.

table inet filter {
    set blocklist {
        type ipv4_addr
        flags timeout
        elements = { 203.0.113.50 timeout 1h }
    }

    set admin_ips {
        type ipv4_addr
        elements = { 192.0.2.10, 198.51.100.5 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        ip saddr @blocklist drop
        ct state established,related accept
        iif "lo" accept
        ip saddr @admin_ips tcp dport 22 accept
        tcp dport { 80, 443 } accept
        tcp dport 3306 drop
        tcp dport 6379 drop
    }
}

Add a live block without reloading:

sudo nft add element inet filter blocklist { 203.0.113.99 timeout 24h }

Rate limiting SSH brute force

SSH attacks hit every public VPS within minutes of provisioning. A metered set is cleaner than fail2ban for simple cases.

    set ssh_flood {
        type ipv4_addr
        flags dynamic
        timeout 15m
    }

    chain input {
        tcp dport 22 ip saddr != @admin_ips add @ssh_flood { ip saddr limit rate 4/minute burst 8 packets } drop
        tcp dport 22 accept
    }

I still run fail2ban on several Deployer-managed hosts for Apache log parsing. nftables handles the network layer; fail2ban handles application logs. Both layers appear in our UFW rules for web servers guide with equivalent logic.

NAT for internal services

If you run Docker or LXC containers, you may need masquerade on the outbound interface. Put NAT in a separate table with the correct hook priority.

table ip nat {
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
        oifname "eth0" masquerade
    }
}

Validate regex patterns for log parsers separately with a regex tester before piping them into automation scripts.

Web Server nftables TopologyInternetUntrustednftablesfilter + natUbuntu 24.04 hostNginx + PHP-FPMMySQL localhostPort policy80 / 443 open22 rate limited3306 blocked6379 blockedAdmin IP set bypasses SSH rate limit
Production nftables policy exposes HTTP ports, limits SSH, and blocks database services from the public internet.

How do you migrate from iptables to nftables safely?

Ubuntu ships iptables-nft, a compatibility layer that translates iptables syntax to nftables internally. That layer helps during migration. It is not where you should live long term.

Use the translation tool

Export current rules, convert, review, then apply on a staging box first.

sudo iptables-save > /tmp/iptables.rules
sudo ip6tables-save > /tmp/ip6tables.rules
sudo iptables-translate -f /tmp/iptables.rules > /tmp/nftables.conf

Open the translated file. Remove duplicate loops. Merge IPv6 into inet family tables where possible. The translator produces verbose output. Hand-editing is expected.

Migration checklist

  • Snapshot the VPS or take an provider console access path before changes.
  • Test nft -c -f /etc/nftables.conf for syntax errors (check mode).
  • Disable conflicting firewalls: stop UFW only after nft rules include equivalent permits.
  • Reload PHP-FPM after deploy if you use opcache—unrelated to nft, but part of my standard deploy checklist on Laravel booking platforms.
  • Document the final ruleset in your runbook alongside automated backup jobs.

The Netfilter iptables project page notes that nftables is the preferred interface for new deployments. Plan migration during a maintenance window, not mid-incident.

iptables to nftables Migration PathExport iptables-saveiptables-translateHand-edit and merge IPv6nft -c check on stagingFix syntax errorsApply on productionEnable nftables systemd unit
Migrate through export, translation, staging validation, and only then apply nftables on production.

What are common nftables mistakes on production servers?

Most failures I see are operational, not syntactic. The rules parse fine. Traffic still breaks because hook priority, family choice, or systemd ordering was wrong.

Mixing inet and ip families incorrectly

Use table inet filter when one ruleset should govern both IPv4 and IPv6. Splitting into ip and ip6 tables duplicates logic. Forgetting IPv6 while hardening IPv4 leaves a wide-open parallel path. Crawlers and bots use IPv6 more every year.

Wrong hook priority with Docker

Docker inserts its own iptables/nft rules for published ports. Custom filter rules at the wrong priority can block container traffic or bypass your drop policy. List the full ruleset after starting containers:

sudo nft list ruleset | less

Forgetting loopback and established rules

Dropping ct state established,related accept kills active SSH and HTTP sessions on reload. Dropping loopback breaks local MySQL and Redis sockets even when those ports are blocked externally. Always include both rules near the top of the input chain.

Not testing before reboot

A syntax error in /etc/nftables.conf can leave the host with no rules after reboot. Run sudo nft -f /etc/nftables.conf manually first. Confirm systemctl status nftables is clean. Schedule reboot tests during support and maintenance windows.

Pair host firewalls with application hardening on your web applications. A correct nftables config does not fix SQL injection or missing CSRF tokens.

Key Takeaways

  • nftables replaces four legacy iptables-family tools with one atomic ruleset managed by the nft CLI.
  • Define tables in the inet family to filter IPv4 and IPv6 together with a single input chain policy.
  • Use native sets for blocklists, admin IPs, and SSH rate limiting instead of maintaining separate ipset files.
  • Migrate with iptables-translate, validate on staging with nft -c -f, and keep a console session open during first production load.
  • Expose only ports 80, 443, and rate-limited SSH; block MySQL 3306 and Redis 6379 from the public internet on single-host stacks.
  • Document the final ruleset next to systemd unit configs and backup cron jobs so the next engineer can recover quickly.

People Also Ask

Is nftables better than iptables?

Yes, for new deployments. nftables offers atomic updates, unified IPv4/IPv6 syntax, built-in sets, and better performance with large rule lists. iptables remains usable through compatibility layers, but the Netfilter project treats nftables as the forward path.

Does Ubuntu UFW use nftables?

On recent Ubuntu releases, UFW can backend onto nftables depending on configuration. UFW still hides complexity behind simple commands. Drop to raw nft when you need sets, custom hooks, or cross-family rules UFW cannot express cleanly.

Can nftables and iptables run at the same time?

They share one kernel Netfilter engine. Mixing live iptables rules with nftables rules causes conflicts and unpredictable ordering. Pick one interface, flush the other, and load a single coherent ruleset.

How do you debug a dropped packet in nftables?

Add a temporary log rule before your drop policy: log prefix "nft-drop: " flags all. Watch with journalctl -k -f. Remove logging after diagnosis—verbose kernel logging fills disks on busy hosts.

Ship a defensible perimeter on every VPS

nftables: The Modern Linux Firewall belongs in every Ubuntu runbook alongside SSH keys, unattended upgrades, and monitored backups. The syntax is cleaner than iptables. The operational model—one file, one atomic load—matches how reliable infrastructure should behave. Start with a minimal filter table, add sets as threats appear, and migrate legacy iptables through the translator before the compatibility layer bitrots.

If you want help hardening production hosts that run your Laravel, WordPress, or API workloads, review our Linux system administration service or browse the portfolio of deployed platforms. For related reading, see systemd service management, Linux interview questions for DevOps, and AIOps for modern infrastructure. Need hands-on help? Contact us to audit your firewall and deployment pipeline together.

Frequently Asked Questions

Netfilter's unified packet-filtering framework. One nft binary replaces iptables, ip6tables, arptables, and ebtables. You define tables, chains, and rules in /etc/nftables.conf and load them atomically with nft -f.

Yes, for new deployments. Atomic updates, unified IPv4 and IPv6 syntax, built-in sets and maps, and better performance with large rule lists. iptables remains usable through compatibility layers, but Netfilter treats nftables as the forward path.

Use UFW for simple cases. Drop to raw nft when you need named sets, rate limiting, custom hooks, or cross-family rules UFW cannot express cleanly.

Run apt update and apt install nftables, then systemctl enable nftables. Confirm the nf_tables kernel module with lsmod, inspect defaults via sudo nft list tables, write a minimal /etc/nftables.conf, load it with sudo nft -f /etc/nftables.conf, and restart the unit. Keep a second SSH session open while testing—locking yourself out is the oldest firewall mistake, and a missing port 22 rule is not forgiven on reload.

Start with a deny-by-default inbound policy on an inet filter table. Allow ct state established,related, loopback, ports 80 and 443, and rate-limited SSH. Block direct access to MySQL on 3306 and Redis on 6379 from the public internet. Use named sets for blocklists and admin IPs so you can add abusive addresses at runtime with nft add element without reloading the entire file. Include ICMP echo for IPv4 and the required icmpv6 types so IPv6 is not left wide open.

Define a dynamic set such as ssh_flood with a timeout, then meter connections to port 22 from IPs outside your admin_ips set. A typical pattern adds offending addresses at limit rate 4/minute burst 8 packets and drops further attempts. This handles network-layer flooding cleanly. On Deployer-managed hosts I still run fail2ban for Apache log parsing—nftables covers the packet layer while fail2ban covers application logs.

Export current rules with iptables-save and ip6tables-save, convert using iptables-translate, then hand-edit the verbose output—merge IPv6 into inet family tables and remove duplicate loops. Snapshot the VPS or ensure console access first. Validate syntax with nft -c -f /etc/nftables.conf on staging before production. Stop UFW only after nft rules include equivalent permits. Plan the cutover during a maintenance window, not mid-incident, and document the final ruleset in your runbook.

On Ubuntu 22.04 and 24.04, nftables is the default packet-filtering stack and UFW can delegate to it depending on configuration. UFW still hides complexity behind simple commands like allow and deny. That split works well when you want UFW for baseline rules and raw nft for advanced cases such as native sets, meters, or custom NAT tables that UFW cannot express without dropping to its own rule files.

No. Both front ends share one kernel Netfilter engine. Mixing live iptables rules with nftables rules causes conflicts and unpredictable ordering. Pick one interface, flush the other, and load a single coherent ruleset. Ubuntu ships iptables-nft as a compatibility layer for migration, but that is a transitional tool—not where you should live long term once your nftables.conf is validated.

Define a blocklist set with type ipv4_addr and flags timeout in your filter table, reference it early in the input chain with ip saddr @blocklist drop, then add elements at runtime: sudo nft add element inet filter blocklist { 203.0.113.99 timeout 24h }. Dynamic sets accept element updates without reloading the entire ruleset. This is cleaner than maintaining separate ipset files and row-by-row iptables edits that are not atomic.

table inet filter governs both IPv4 and IPv6 from one input chain and one policy. Splitting into ip and ip6 tables duplicates logic and increases the chance you harden IPv4 while leaving IPv6 wide open. Crawlers and bots use IPv6 more every year. A single inet ruleset with icmpv6 types for neighbor discovery alongside standard TCP permits keeps both address families consistent without maintaining parallel files.

Most failures are operational, not syntactic. Mixing inet and ip families incorrectly leaves IPv6 exposed. Wrong hook priority with Docker can block container traffic or bypass your drop policy—list the full ruleset after starting containers. Forgetting ct state established,related accept or loopback breaks active sessions and local MySQL or Redis sockets. A syntax error in /etc/nftables.conf can leave the host with no rules after reboot, so run nft -f manually and test systemd status before relying on it.

Docker inserts its own iptables or nft rules for published ports. Custom filter rules at the wrong priority can block container traffic or bypass your drop policy entirely. After starting containers, inspect the merged ruleset with sudo nft list ruleset. Put NAT masquerade in a separate ip nat table with type nat hook postrouting priority srcnat on the outbound interface such as eth0. Validate the full chain order rather than assuming your filter table alone controls all traffic.

Add a temporary log rule before your drop policy, for example log prefix "nft-drop: " flags all, then watch kernel output with journalctl -k -f. The log shows which rule caught the packet so you can adjust permits or fix hook ordering. Remove logging after diagnosis—verbose kernel logging fills disks quickly on busy hosts serving Laravel or WordPress traffic with high connection volumes.

Not necessarily—they cover different layers. nftables meters and sets handle network-layer SSH flooding and IP blocklists efficiently. fail2ban still adds value parsing Apache or application logs for patterns nft cannot see. On production boxes I run both: nftables for perimeter policy exposing only 80, 443, and rate-limited SSH, fail2ban for log-driven bans. Host firewalls do not fix SQL injection or missing CSRF tokens, so pair either tool with application hardening.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: