Linux Kernel Tuning Cheat Sheet for Web Infra [2026]
Bottom Line
For high-concurrency web workloads, the biggest wins usually come from aligning accept queues, SYN queues, ephemeral ports, and file descriptor ceilings instead of hunting obscure sysctls. Tune the bottleneck you can measure, and keep application backlog settings, systemd limits, and kernel limits consistent.
Key Takeaways
- ›Since Linux 5.4,
net.core.somaxconndefaults to 4096, not 128. - ›
listen()backlog is capped bysomaxconn; incomplete handshakes usetcp_max_syn_backlog. - ›Kernel docs treat
tcp_syncookiesas a fallback for SYN floods, not a normal scaling knob. - ›Fix port pressure with
ip_local_port_rangeandip_local_reserved_portsbefore risky TIME_WAIT tweaks. - ›Concurrency breaks when
fs.file-max,RLIMIT_NOFILE, and serviceLimitNOFILEdisagree.
High-concurrency Linux tuning is mostly about removing bottlenecks you can prove: accept queues, SYN queues, ephemeral ports, file descriptors, and per-service limits. This reference keeps the scope operational, with copy-ready commands, a live filter, keyboard shortcuts, and persistence patterns that survive reboots. Where kernel behavior matters, it follows current kernel documentation and the user-space contract described by listen(2), so you can tune without guessing.
- Since Linux 5.4,
net.core.somaxconndefaults to 4096 instead of 128. listen()backlog is capped bysomaxconn; incomplete handshakes are controlled separately bytcp_max_syn_backlog.tcp_syncookiesis a fallback for SYN flood conditions, not a steady-state throughput setting.- Port pressure is often better solved with
ip_local_port_rangeandip_local_reserved_portsthan with aggressive TIME_WAIT changes. - Kernel limits fail closed when your service manager and process
NOFILElimits are still low.
Quick Audit First
Bottom Line
For high-concurrency web workloads, the fastest path is to line up somaxconn, tcp_max_syn_backlog, ephemeral port capacity, and file descriptor ceilings with the application’s own backlog and accept behavior. If those layers disagree, raising a single sysctl rarely fixes the incident.
The first pass should answer four questions before you change anything.
- Is the application actually requesting a large enough
listen()backlog? - Are you dropping incomplete handshakes, overflowing established accept queues, or simply exhausting ports or FDs?
- Are the limits temporary session settings, or persistent config that will survive the next reboot?
- Are you diagnosing a kernel bottleneck, or an app bottleneck such as a slow accept loop, single-threaded worker model, or overloaded upstream?
uname -r
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog
sysctl net.ipv4.ip_local_port_range net.ipv4.ip_local_reserved_ports
sysctl fs.file-max fs.nr_open
ulimit -n
ss -s
ss -lnt
Live Search and Keyboard Shortcuts
This cheat sheet is designed to be scanned under pressure. Use the filter to narrow commands by keyword such as backlog, ports, fd, systemd, or rollback.
Keyboard: / focuses search, Esc clears it, n jumps to the next visible card, p jumps to the previous one.
| Key | Action | Best use |
|---|---|---|
/ | Focus the live filter | Jump straight to a keyword during an incident |
Esc | Clear filter | Reset to the full cheat sheet view |
n | Next visible card | Step through matching command groups |
p | Previous visible card | Move back without scrolling manually |
Commands Grouped by Purpose
The commands below are grouped by the failure mode they help you confirm. Kernel docs are clear on the queue split: somaxconn caps the backlog requested by listen(), while tcp_max_syn_backlog governs incomplete handshakes.
Backlog and accept queues
- Check whether the service backlog is being capped by
net.core.somaxconn. - Inspect incomplete handshakes separately with
net.ipv4.tcp_max_syn_backlog. - Look for kernel warnings that point to SYN pressure or slow accept loops.
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
ss -lnt
journalctl -k | grep -E 'SYN|overflow|possible SYN flooding'
Ephemeral ports and reserved service ports
- Use this when many short-lived outbound connections are competing for local ports.
- Expand the ephemeral range before you blame TIME_WAIT alone.
- Reserve fixed service ports so automatic assignments never collide with them.
sysctl net.ipv4.ip_local_port_range
sysctl net.ipv4.ip_local_reserved_ports
cat /proc/sys/net/ipv4/ip_local_port_range
cat /proc/sys/net/ipv4/ip_local_reserved_ports
ss -tan state time-wait | wc -l
File descriptors and file-handle ceilings
- System-wide file handles and per-process
NOFILElimits must both be high enough. fs.file-maxis system-wide;RLIMIT_NOFILEis per process.- On systemd hosts, the unit-level
LimitNOFILEoften becomes the hidden bottleneck.
sysctl fs.file-max fs.nr_open
cat /proc/sys/fs/file-nr
ulimit -n
systemctl show --property=LimitNOFILE nginx
Socket state summary during incidents
- Use this set when you need a fast shape-of-traffic snapshot.
ss -sgives a compact socket-state summary.- Pair it with listener inspection to confirm whether the issue is inbound, outbound, or both.
ss -s
ss -tan | head
ss -lntp
journalctl -k --since '15 min ago'
Safe temporary changes for testing
- Apply runtime changes first so you can confirm impact before writing persistent config.
- Use a short observation window and revert fast if latency or retransmits get worse.
- Track changes in the incident timeline, not just in shell history.
sudo sysctl -w net.core.somaxconn=8192
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sudo sysctl -w net.ipv4.ip_local_port_range='20000 65535'
Configuration That Actually Sticks
Persist only the settings you can defend with workload evidence. The most common production pattern is a dedicated file in /etc/sysctl.d/ plus a service-level override for LimitNOFILE.
Persistent sysctl profile
- Keep web-tier tuning isolated in one file so rollback is obvious.
- Document why each value exists, not just the chosen number.
- Prefer widening port headroom over changing obscure TCP behavior first.
# /etc/sysctl.d/99-web-concurrency.conf
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 20000 65535
net.ipv4.ip_local_reserved_ports = 3000,3001,8080,8443
fs.file-max = 2097152
sudo sysctl --system
systemd service override
- Raise
LimitNOFILEon the unit that owns the sockets. - Match the service limit to the app model, worker count, and upstream connection fan-out.
- Reload the manager after writing the override.
# /etc/systemd/system/nginx.service.d/limits.conf
[Service]
LimitNOFILE=1048576
sudo systemctl daemon-reload
sudo systemctl restart nginx
systemctl show --property=LimitNOFILE nginx
tcp_syncookies as a fallback facility and say it must not be used as the normal answer to legal high connection rate. If your logs show SYN flooding under ordinary traffic, treat that as a tuning or capacity problem first.Advanced Usage and Validation
The advanced path is about proving that the change addressed the right layer. Do not stop at “the sysctl applied.” Confirm that backlog pressure, port exhaustion, or FD saturation actually moved in the expected direction.
Validation loop after a change
- Capture a before-and-after snapshot with the same commands.
- Watch error rates, connection establishment latency, and socket-state distribution together.
- If the app still passes a small backlog to
listen(), a largersomaxconnalone will not help.
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog
sysctl net.ipv4.ip_local_port_range net.ipv4.ip_local_reserved_ports
sysctl fs.file-max fs.nr_open
ss -s
ss -lnt
journalctl -k --since '10 min ago'
Rollback pattern
- Revert runtime tests immediately if they increase retransmits or just move the bottleneck elsewhere.
- For persistent config, remove or edit one dedicated file rather than diffusing changes across the host.
- Keep rollback commands in the same change record as the rollout commands.
sudo sysctl -w net.core.somaxconn=4096
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096
sudo sysctl -w net.ipv4.ip_local_port_range='32768 60999'
sudo rm /etc/sysctl.d/99-web-concurrency.conf
sudo sysctl --system
- TIME_WAIT reuse: current kernel docs list
tcp_tw_reusevalues 0, 1, and 2, with 2 meaning loopback-only reuse and a warning that it should not be changed without expert advice. - Ephemeral range defaults: current kernel docs list
ip_local_port_rangedefaults as32768 60999, which is often too tight for chatty outbound estates. - Containers: some sysctls are namespaced, some are host-wide, and container runtimes may expose only a subset. Validate where the limit actually lives before changing it.
- Documentation path: if you want to verify semantics directly, start with the Linux kernel IP sysctl docs and the proc sysctl man pages.
- Snippet hygiene: if you want to reshape the copied shell blocks for team docs or runbooks, the TechBytes Code Formatter is the fastest cleanup step.
Frequently Asked Questions
What is the difference between somaxconn and tcpmaxsyn_backlog? +
somaxconn caps the backlog value passed to listen(), which on modern Linux applies to fully established connections waiting in the accept queue. tcp_max_syn_backlog is the separate limit for incomplete TCP handshakes in SYN_RECV. The split matters because raising one queue does not automatically expand the other.Should I enable tcptwreuse on internet-facing web servers? +
tcp_tw_reuse cautiously. Current kernel docs describe it as safe only from the protocol viewpoint under specific conditions, list 2 as loopback-only reuse, and explicitly say it should not be changed without expert advice. In practice, widening ip_local_port_range and reserving fixed ports is the safer first move.Why do I still get connection errors after increasing somaxconn? +
somaxconn is only one layer. The application may still pass a small backlog to listen(), the SYN queue may be too small, the service may accept too slowly, or the host may be out of ephemeral ports or file descriptors. Verify queues, ports, and NOFILE limits together before concluding the kernel is the bottleneck.Where should Linux kernel tuning changes be persisted on production hosts? +
/etc/sysctl.d/, then load it with sysctl --system. For per-service file descriptor limits on systemd hosts, use a unit override with LimitNOFILE=. Keeping both in dedicated files makes rollback and peer review much cleaner.Get Engineering Deep-Dives in Your Inbox
Weekly breakdowns of architecture, security, and developer tooling — no fluff.