Linux firewall and NAT capacity tool
Connection Tracking Table Calculator
Size Linux nf_conntrack_max and hash buckets from concurrent flows, new flow churn, protocol timeout mix, NAT extension overhead, safety buffer, and target bucket load.
Entry sizing model
The calculator treats NAT as memory overhead, not extra conntrack entries. Required table depth is the larger of measured concurrency or churn retained by weighted timeouts, then safety buffer is applied.
Calculation breakdown
Protocol and memory detail
| Protocol mix | TCP share | UDP share | When to use |
|---|---|---|---|
| TCP heavy | 80% | 15% | General home routing, browsers, updates, media apps, and normal NAT egress. |
| Balanced | 60% | 35% | Mixed web traffic, tunnels, DNS, mobile apps, and small service meshes. |
| UDP heavy | 35% | 60% | WireGuard, voice, games, QUIC-heavy clients, telemetry, and broadcast discovery. |
| P2P mixed | 55% | 40% | Torrent labs, sync tools, distributed storage, and many short-lived peer flows. |
| Preset | Concurrent flows | New flows/sec | Primary pressure |
|---|---|---|---|
| Home Router 1K Flows | 1,000 | 20 | Mostly TCP NAT with modest bursts from phones, PCs, and streaming devices. |
| Kubernetes Node NAT | 80,000 | 900 | Pods, image pulls, service calls, probes, and node-level SNAT churn. |
| WireGuard Gateway | 25,000 | 180 | UDP tunnel flows plus routed client TCP sessions behind the VPN gateway. |
| Torrent Client Lab | 120,000 | 1,500 | Many peer tuples, UDP trackers, DHT, and short connection churn. |
| Linux setting | Example command | What it controls | Planning note |
|---|---|---|---|
| nf_conntrack_max | sysctl net.netfilter.nf_conntrack_max | Maximum tracked entries before insert failures begin. | Set above required entries plus operational headroom. |
| hashsize | modprobe nf_conntrack hashsize=65536 | Hash bucket count used to distribute conntrack entries. | Often fixed at module load; plan before boot images. |
| TCP established | nf_conntrack_tcp_timeout_established | Idle retention for established TCP flows. | Long defaults can dominate sizing on busy NAT hosts. |
| UDP timeout | nf_conntrack_udp_timeout_stream | Retention for stream-like UDP conversations. | QUIC, WireGuard, DNS, and games may need separate tuning. |
| Bucket load | Meaning | Recommended use | Tradeoff |
|---|---|---|---|
| 2 entries/bucket | Very short chains | Latency-sensitive gateways and busy firewalls. | More bucket memory. |
| 4 entries/bucket | Balanced default target | Home servers, NAT nodes, and office edge routers. | Good memory and lookup balance. |
| 8 entries/bucket | Compact bucket table | Memory-constrained devices with predictable traffic. | Longer chain walks during bursts. |
| 12+ entries/bucket | High collision tolerance | Only when memory is tight and flow churn is low. | Can raise CPU under scans and peer traffic. |
nf_conntrack_count, firewall insert-failed logs, and peak new-flow telemetry. Concurrency tells you today; timeout-weighted churn tells you what the table must retain during a burst.When you drop some packets or experience lower throughput, you probably check your firewall log. You find that your Linux gateway has run out of room for tracking current conversation. Regardless of how short the chat, even just a quick DNS lookup, the kernel need to keep track. When there’s no room in the table, new conversations will be denied and users can’t get their work done.
Whenever the connection tracking subsystem observe a flow, it creates an entry to represent that flow. Such entries consume memory and remain in a hash table until they time out. By default, the timeouts are too long. For example, the timeout for an established TCP connection may be five days. That means that if you leave one tab open in your browser, it will occupy a slot for more than four hundred thousand seconds. Now consider how fast these slots gets filled up with lots of device making short-lived connections. It’s not due to heavy traffic… The table just seems full because old data isn’t removed quickly enough.
How to Set Your Connection Table Size
There are two types of pressures you need to consider for sizing the table: (1) Concurrency; i.e., the current set of connections, and (2) Churn, i.e., rate of incoming new flows and duration of each flow. One extreme case could be high churn with steady traffic, such as a Kubernetes node with pods constantly restarting. In another extreme case, there could be lots of concurrent traffic with little churn, such as a home router with many long streaming session. You should of handle both cases.
The problem with NAT is that it makes things more complex since each translated flow require additional space for its extension data. That’s not just “counting” flows, it’s “measuring” their memory weight. After setting your timeouts and flow rates, the calculator does math for you. You don’t need to calculate your weighted average by hand anymore.
While most folks obsess about the maximum number of entries they forget that hash table buckets exist. Consider the conntrack table to be a hotel with rooms. The entries is like the rooms and the hash buckets are like the hallways leading to those rooms. Having too few corridors means that each guest has to walk past lots of locked doors before finding theirs. This wastes CPU cycles and causes slow packet processing. A low load factor keeps lookups speedy regardless of table size.
It isn’t just the quantity of protocols that is important, but their mix as well. While TCP flows have a longer expiration time compared to UDP, poorly configured bursty UDP traffic could overwhelms the stream. Traffic like WireGuard tunnels or heavy QUIC traffic, which is increasingly common on today’s networks, requires special care. An overly generous timeout will fill the table with stale entries, while an overly strict timeout will drop active sessions. It’s a balancing act: how much do you want to retain versus how responsive you need to be?
The end result is usually determined by memory. Adding each entry consume some amount of memory; when you multiply that by hundreds of thousands of flows, it adds up to megabytes or even gigabytes. And on a low-RAM server, aggressive timeout reduction may be the only option instead of purchasing additional hardware. But lowering the timeout is risky business too. You don’t want to kill a video call because the kernel decided that the link has been idle for half a minute. It’s just a matter of knowing what is actualy being measured, and for how long it should be recorded.
Begin with your TCP established timeout. If this has defaulted, lower it. Next, look at your UDP stream timeouts. Your NAT percentage should be set based off how much traffic you are routing versus translating. With these realistic values in place, now you can get the number of entries that serve as a solid starting point for your config.
You don’t want to create too few so that you panic during a traffic spike but you also don’t want to go overboard because then the table will never empty out (meaning it won’t be efficient). Ideally you want the table to be smooth; when every packet finds its way quickly, the network appears fast and reliable. This is the true benefit of proper sizing.


