nftables counters let you track traffic with human-readable names, making it way easier to understand what’s going on than just raw byte/packet counts.

Let’s watch some packets flow. Imagine we have a simple nftables rule that accepts all traffic on port 22 (SSH) and we want to count how many packets hit it.

table ip filter {
    chain input {
        type filter hook input priority 0; policy accept;

        # Named counter for SSH traffic
        tcp dport 22 counter name ssh_hits accept

        # Drop everything else
        drop
    }
}

Now, when SSH traffic arrives, ssh_hits increments. We can see this in action using the nft list ruleset command.

$ sudo nft list ruleset
table ip filter {
    chain input {
        type filter hook input priority 0; policy accept;
        tcp dport 22 counter name ssh_hits accept
        drop
    }
}

And to see the actual counts:

$ sudo nft list counters ip filter input
counter ssh_hits {
    packets 15
    bytes 1230
}

Here, ssh_hits has seen 15 packets totaling 1230 bytes. If we send more SSH traffic, these numbers will go up.

The Problem Counters Solve

Without named counters, you’d be left staring at raw packet and byte counts associated with specific rules. If you have a complex ruleset with dozens of rules, trying to correlate a general packet count to a specific type of traffic (like "how many legitimate SSH connections are we seeing?") becomes a painful exercise in pattern matching. Named counters provide an immediate, semantic link between traffic flow and its observed volume.

How They Work Internally

When nftables processes a packet and it matches a rule containing the counter keyword, the kernel’s nftables module increments two internal counters associated with that rule: one for packets and one for bytes. If a name is provided, these internal counters are then aliased to that human-readable string. This allows for easy retrieval and monitoring through the nft command-line utility. The nft list counters command queries the kernel’s netfilter subsystem for these named counter values.

The Levers You Control

  1. Naming: The name parameter is crucial. It’s how you give meaning to the counts. Choose descriptive names like http_requests, malicious_ips_blocked, or vpn_traffic_in. The name must be unique within a given chain.

  2. Placement: Where you put the counter statement in your ruleset matters. It will count packets that match that specific rule. If you place it before a reject or drop rule, you’ll count traffic that’s about to be discarded. If you place it before an accept rule, you’ll count traffic that’s being allowed.

  3. Byte vs. Packet Counting: By default, counter tracks both packets and bytes. You can explicitly choose to only count packets with counter packets or only bytes with counter bytes, though this is less common as seeing both provides a richer picture.

  4. Resetting: Counters are persistent across rule reloads but can be reset to zero. You can do this individually per counter:

    sudo nft counter ip filter input ssh_hits delete
    

    Or reset all counters in a chain:

    sudo nft flush counters ip filter input
    

The Counter’s True Power is Aggregation

While individual counters are useful, their real strength emerges when you combine them with other nftables features. For example, you can use counter statements within meter rules to track how many packets exceed a defined rate. Or, you can use them in conjunction with quota rules to monitor how much data has been transferred before a limit is hit. This allows for sophisticated traffic shaping and monitoring directly within the firewall.

The next step after monitoring is often acting on these counts, which leads to exploring nftables’ quota and meter features for rate limiting and bandwidth management.

Want structured learning?

Take the full Nftables course →