Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Nftables Cheatsheet

Table of Contents

  1. Getting Started
    1. Installation
    2. Enable And Start Nftables
  2. Table Commands
    1. List Tables
    2. Add Table
    3. Delete Table
  3. Import / Export
    1. Import
    2. Export
    3. Make Rules Persistent
    4. Default Nftables Config
    5. Schema
  4. Nftables Families
  5. Common Useful Commands
    1. Open Port
  6. Convert Iptables to Nftables
  7. Nftables and Docker

Getting Started  

Installation  

On Debian/Ubuntu based systems, you should be able to install nftables by running:

 sudo apt update && sudo apt install nftables

Debian documentation states that nftables is used by default as of Debian 10 Buster, but when I tried to run any nft commands, they wouldn't work and I still needed to install the nftables package. It looks like Debian is using nftables in the kernel backend, but still operating using iptables userspace syntax. I may be wrong, and appear to not be the only one confused by this. If you know better, please post in the comments.

Enable And Start Nftables  

sudo systemctl enable nftables
sudo systemctl start nftables

Terms

Chain "Priority"

When creating chains, you will need to assign a priority. The priority needs to be 0 or above, and chains with a lower priority get processed first. Thus, you may wish to think of it as "order" rather than "priority".

Import / Export

Import

Import NFT File Ruleset

sudo nft --file ruleset.nft

Also, if you want to read from stdin, you can do so like so:

cat ruleset.nft | sudo nft --file -

Import JSON File Ruleset

sudo nft --json --file rules.json

Also, if you want to read from stdin, you can do so like so:

cat ruleset.json | sudo nft --json --file -

Export

Export NFT

To export the rules, one can do the following:

sudo nft list ruleset > ruleset.nft

Export JSON

If you want to export the rules in JSON format, add the --json flag like so:

sudo nft --json list ruleset > ruleset.json

This will output the rules in a compressed JSON format. If you want to be able to easily be able to read/edit the rules, you can use the jq tool like so:

sudo nft --json list ruleset | jq . > ruleset.json

You may need to install jq by running: sudo apt install jq -y

Make Rules Persistent

The rules defined within the configuration file at /etc/nftables.conf are what are used when a server restarts. Thus, we can use the export command and a few manual additions to overwrite this configuration file to make our dynamically added rules permanent like so:

# First set the shebang
echo '#!/usr/sbin/nft -f' > ruleset.nft

# Tell nftables to reset
echo "flush ruleset" >> ruleset.nft

# Add the existing rules after a spacer/newline
echo "" >> ruleset.nft
nft list ruleset >> ruleset.nft

# Overwrite the configuration file with our generated file.
mv ruleset.nft /etc/nftables.conf

Default Nftables Config

The default /etc/nftables.conf file is:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
        chain input {
                type filter hook input priority filter;
        }
        chain forward {
                type filter hook forward priority filter;
        }
        chain output {
                type filter hook output priority filter;
        }
}

In JSON format, this would be represented as:

{
  "nftables": [
    {
      "metainfo": {
        "version": "1.0.6",
        "release_name": "Lester Gooch #5",
        "json_schema_version": 1
      }
    },
    {
      "table": {
        "family": "inet",
        "name": "filter",
        "handle": 1
      }
    },
    {
      "chain": {
        "family": "inet",
        "table": "filter",
        "name": "input",
        "handle": 1,
        "type": "filter",
        "hook": "input",
        "prio": 0,
        "policy": "accept"
      }
    },
    {
      "chain": {
        "family": "inet",
        "table": "filter",
        "name": "forward",
        "handle": 2,
        "type": "filter",
        "hook": "forward",
        "prio": 0,
        "policy": "accept"
      }
    },
    {
      "chain": {
        "family": "inet",
        "table": "filter",
        "name": "output",
        "handle": 3,
        "type": "filter",
        "hook": "output",
        "prio": 0,
        "policy": "accept"
      }
    }
  ]
}

Schema

Information about the JSON schema can be found online.

Table Commands

List Tables  

You can use the following command to list your tables:

sudo nft list tables

Add Table

ADDRESS_FAMILY="inet"
TABLE_NAME="my_table"
sudo nft add table $ADDRESS_FAMILY $TABLE_NAME

Refer to Nftables Families section for more info on ADDRESS_FAMILY

Delete Table

ADDRESS_FAMILY="inet"
TABLE_NAME="my_table"
sudo nft delete table $ADDRESS_FAMILY $TABLE_NAME

Refer to Nftables Families section for more info on ADDRESS_FAMILY

Chain Commands

Chains filter packets and live under tables. You attach each rule to a chain so that packets are caught in the chains filter and are subsequently passed to the chain's rules.

Create Base Chain

Base chains act as entry points for packets coming from the network stack.

ADDRESS_FAMILY="inet"
TABLE_NAME="my_table"
CHAIN_NAME="my_chain"
TYPE="filter"
HOOK="input"
PRIORITY=0
sudo nft add chain $ADDRESS_FAMILY $TABLE_NAME $CHAIN_NAME '{type $TYPE hook $HOOK priority $PRIORITY; }'

Create Regular Chain

Regular chains do not act as filters, but can act as jump targets. They can help with controlling the flow and organization of your nftables.

ADDRESS_FAMILY="inet"
TABLE_NAME="my_table"
CHAIN_NAME="my_chain"
sudo nft add chain $ADDRESS_FAMILY $TABLE_NAME $CHAIN_NAME

Nftables Families  

Netfilter enables filtering at multiple networking levels. With iptables there is a separate tool for each level: iptables, ip6tables, arptables, ebtables. With nftables the multiple networking levels are abstracted into families, all of which are served by the single tool nft. The following are descriptions of current nftables families, but additional families may be added in the future.

  • ip
    • Tables of this family see IPv4 traffic/packets. The iptables tool is the legacy x_tables equivalent.
  • ip6
    • Tables of this family see IPv6 traffic/packets. The ip6tables tool is the legacy x_tables equivalent.
  • inet
    • Tables of this family see both IPv4 and IPv6 traffic/packets, simplifying dual stack support.
  • arp
    • Tables of this family see ARP-level (i.e, L2) traffic, before any L3 handling is done by the kernel. The arptables tool is the legacy x_tables equivalent.
  • bridge
    • Tables of this family see traffic/packets traversing bridges (i.e. switching). No assumptions are made about L3 protocols.
  • netdev
    • The netdev family is different from the others in that it is used to create base chains attached to a single network interface. Such base chains see all network traffic on the specified interface, with no assumptions about L2 or L3 protocols. Therefore you can filter ARP traffic from here. There is no legacy x_tables equivalent to the netdev family.

Common Useful Commands

Open Port

If you set your server policy to default drop/reject on the input table, then you will need to open up ports that you wish to allow. E.g. the command below will open up port 22 so that you can connect to the server:

sudo nft add rule 'inet filter input tcp dport 22 accept'

If you wish to take it a step further, and specify that the destination IP should be our server, then you could do:

sudo nft add rule 'inet filter input ip daddr $MY_IP  tcp  dport 22  accept'

If you wish to only allow connecting on port 22 from a certain IP address, such as perhaps your VPN's IP address, then you would do this like so:

ALLOWED_IP="192.168.2.2"
sudo nft add rule  inet filter input ip saddr $ALLOWED_IP tcp dport 22 accept

Also, you can use CIDR notation to open up port 22 from a certain IP range. E.g. this would open up port 22 to only IP addresses on the 192.168.1.1-192.168.1.255 range.

sudo nft add rule  inet filter input ip saddr 192.168.1.1/24 tcp dport 22 accept

If you wish to specify the interface that the packet must have come in on, then you can add iifname "$INTERFACE_NAME" like so:

sudo nft add rule 'inet filter input iifname lan0 tcp dport 22 accept'

Combining them all together would be something like so:

sudo nft add rule 'inet filter input iifname lan0 ip saddr 192.168.1.1/24 ip daddr 192.168.1.23 tcp dport 22 accept'

Convert Iptables to Nftables

Install Package

You can use the following command to install a porting tool

sudo apt install iptables-nftables-compat

I found that this was not available on Debian (11 or 12), but was available on Ubuntu 22.04 (and appears to be available on other Ubuntu versions.

Create Iptables File Of Existing Iptables Rules

Use the following command to create a dump/backup of your existing iptables rules

sudo iptables-save > iptables-rules.txt

Convert Iptables File To Nftables Ruleset

Use the porting tool we installed earlier to port the iptables rules over to nftables rules:

sudo iptables-restore-translate -f iptables-rules.txt > ruleset.nft

Then you may wish to import the ruleset, before then possibly exporting the JSON form.

Nftables and Docker

Docker manipulates iptables for the networking to "magically" work. It is currently configured to only work with iptables and not nftables. However you may be able to work around this. Please refer to the following resources:

As others have pointed out, it is probably easiest to leave nftables out of the server running docker, and have an external firewall service that you use to manage the traffic going into and out of your server.

References

Last updated: 13th July 2024
First published: 20th April 2022