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.
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.
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.
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.
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.
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.