← back

Tuning conntrack on busy Linux boxes

April 22, 2026

If you've ever stared at nf_conntrack: table full, dropping packet in dmesg you already know how this story goes. Here are the knobs I check first, roughly in the order I learned to care about them.

nf_conntrack_max

The headline limit. On a default Ubuntu 24.04 box it's something around 262144 — fine for a workstation, painful for any kind of relay. Set it explicitly in /etc/sysctl.d/:

net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_buckets = 262144

Bucket count should be roughly 1/4 of max. The kernel will warn in dmesg if the ratio is off.

Timeouts

The defaults assume a desktop. For a relay, halve the established TCP timeout and shrink TIME_WAIT aggressively:

net.netfilter.nf_conntrack_tcp_timeout_established = 7200
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
net.netfilter.nf_conntrack_udp_timeout = 30
net.netfilter.nf_conntrack_udp_timeout_stream = 120

Don't lower the established timeout below ~1h or you'll cut long-lived SSH and gRPC sessions.

Skip conntrack entirely?

For pure pass-through workloads (an L4 LB doing no NAT, no stateful firewall) you can --notrack in the raw table and bypass the whole subsystem. It's the right call when you genuinely don't need state, but I find that's rarely true in practice — at minimum you usually want SYN-flood protection.

Watching

The metric that matters is /proc/sys/net/netfilter/nf_conntrack_count over time. Scrape it, graph it, alert at 80% of max. Anything that catches the table filling before you start dropping packets is gold.

Final note

Conntrack tuning is one of those areas where the defaults are conservative on purpose. Bumping them on a 4-core VM with 4 GB of RAM and expecting magic won't work — RAM cost per entry is small but real (~300 bytes), and CPU does suffer when the table is large and the lookup ratio is bad.