SecurityMay 19, 20263 min read

nftables firewall basics for Linux servers

nftables is the modern replacement for iptables. Learn its table/chain model and write a clean, readable firewall ruleset for a VPS from scratch.

NBy Nxeon

nftables is the modern packet-filtering framework in the Linux kernel, the official successor to iptables. It's faster, has cleaner syntax, and handles IPv4 and IPv6 in one place. If UFW feels too abstract and iptables feels dated, nftables is the sweet spot for direct control.

The model: tables, chains, rules

Three concepts:

  • A table groups related rules for a protocol family (inet covers both IPv4 and IPv6).
  • A chain hooks into a point in packet processing, most importantly input (traffic arriving at the server).
  • A rule matches packets and takes an action like accept or drop.

The strategy for a server is default-drop: reject everything on input, then explicitly accept only what you need.

Check what's there

sudo nft list ruleset

On a fresh system this may be empty or minimal.

Build a ruleset step by step

Create a table and a filtered input chain with a default drop policy:

sudo nft add table inet filter
sudo nft 'add chain inet filter input { type filter hook input priority 0 ; policy drop ; }'

Now add the essential accepts. Keep existing/related connections and loopback:

sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input iif lo accept

Allow SSH, HTTP and HTTPS:

sudo nft add rule inet filter input tcp dport 22 accept
sudo nft add rule inet filter input tcp dport { 80, 443 } accept

Allow ping (optional but handy for monitoring):

sudo nft add rule inet filter input ip protocol icmp accept
sudo nft add rule inet filter input ip6 nexthdr icmpv6 accept

The cleaner way: a config file

Adding rules one by one is fine for testing, but a config file is easier to read and reload. Write /etc/nftables.conf:

#!/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
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept

        tcp dport 22 accept
        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;
    }
}

Load and enable it so it survives reboots:

sudo nft -f /etc/nftables.conf
sudo systemctl enable --now nftables

Test before you trust it

The established,related rule keeps your current SSH session alive while you apply changes, but always verify a new connection works before you disconnect. Open a second terminal and ssh in again. If it fails, use Nxeon's dashboard console to reach the server out-of-band and fix the file.

Restrict a port to one IP

To expose a database only to a trusted address:

sudo nft add rule inet filter input ip saddr 203.0.113.5 tcp dport 5432 accept

Everything else hitting 5432 is dropped by the default policy.

Rate-limit SSH

Slow down brute-force attempts:

sudo nft add rule inet filter input tcp dport 22 ct state new limit rate 4/minute accept

nftables vs UFW — which to use

UFW is perfect when you want simple allow/deny rules and don't care about the internals. nftables is the right call when you want a single readable ruleset, fine-grained matching, unified IPv4/IPv6, or you're building something more complex like NAT. Both ultimately drive the same kernel engine — pick the abstraction that fits how much control you want.

#nftables#firewall#security#linux#vps

Deploy your first server in under a minute

No credit card required to get started. Spin up a VPS, break things, and only pay for what you keep running.