Linux VPS Kernel Tuning: sysctl Parameters That Actually Improve Throughput

Default sysctl values on a Linux VPS are tuned for a general-purpose machine that does not exist. Distros ship conservative network buffers, small connection backlogs, and modest file descriptor ceilings so that a fresh install behaves predictably across every possible environment. That is a reasonable default, but it means a busy web stack or a database on a modest instance will begin queueing and dropping long before the CPU is saturated. The parameters below are the ones that produce measurable changes, in the order worth applying, with the reasoning behind each so you can size them for your own workload rather than pasting a forum tuning script. Every value here should be justified by an observation; if you cannot name the counter that improves, skip the change. For broader context on how these limits interact with plan choice, the VPS architecture overview on this site is a useful starting point.

Baseline first, and keep a rollback path

Before changing anything, capture current behaviour and the running configuration. A sysctl change that helps throughput can quietly hurt tail latency, and without a before-picture you cannot tell.

sysctl -a > /tmp/sysctl.before
cp /etc/sysctl.conf /etc/sysctl.conf.bak
ss -s; nstat -az > /tmp/nstat.before

Load-test the workload with a realistic concurrency profile, note the p50 and p99 latency and the retransmission counters, then change one parameter group at a time. Grouping changes by subsystem — network, file descriptors, memory — keeps the attribution clean.

Connection backlog and accept queue depth

When a burst of new connections arrives faster than the application accepts them, the kernel queues them in the socket’s backlog. If that queue fills, further SYNs are dropped and clients retry after a timeout, which shows up as multi-second connection spikes that look nothing like server overload.

net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
net.core.netdev_max_backlog = 4096

somaxconn caps the listen backlog; the application’s own listen() argument must match it or the smaller value wins. Raising it without raising the application value accomplishes nothing, which is why so many “tuned” servers still drop connections. Watch ListenOverflows and ListenDrops in nstat; both should stay at zero during your normal peak.

File descriptors before socket buffers

Long before kernel network buffers become the constraint, a single-process server hits its open-file limit. Every accepted socket, every log file, and every open cache handle consumes one descriptor, and the ceiling is inherited from the systemd unit rather than from /etc/security/limits.conf on modern distributions.

systemctl show nginx -p LimitNOFILE
cat /proc/$(pgrep -o nginx)/limits | grep "open files"

Set the unit’s LimitNOFILE to a value your workload genuinely needs, then confirm the running process reports it. Raising the limit far beyond the workload only increases the worst-case memory if a connection flood ever occurs.

Socket buffer sizing for high-latency links

The receive window a TCP connection can advertise is bounded by the socket buffer. On a link with meaningful round-trip time, an undersized buffer caps throughput regardless of available bandwidth: the bandwidth-delay product for a 150 ms path at 100 Mbps is roughly 1.9 MB in flight.

net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 262144 16777216
net.ipv4.tcp_wmem = 4096 262144 16777216

The three values are minimum, default, and maximum. Leave the defaults modest; only the maximum needs to be generous. Oversized defaults let a single idle connection pin megabytes of kernel memory, which on a 2 GB instance is a real cost.

Parameter Symptom it addresses Counter to watch
somaxconn Connection timeouts during bursts ListenOverflows
tcp_rmem max Throughput capped on long RTT Measured BDP vs window
tcp_tw_reuse Ephemeral port exhaustion TCPAbortOnMemory
netdev_max_backlog Packet drops under bursts softnet_stat drops

Connection churn and TIME_WAIT accumulation

A proxy or crawler-heavy workload creates thousands of short-lived outbound connections. Each one that closes from your side leaves a TIME_WAIT entry for twice the maximum segment lifetime, and on a single IP the ephemeral port range can be exhausted within minutes.

net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

tcp_tw_reuse is safe on outbound connections for Linux clients; it lets the kernel recycle a TIME_WAIT socket for a new connection when the timestamp guarantees no confusion. Avoid the old tcp_tw_recycle, which was removed for good reason and breaks clients behind NAT.

Backlog and accept-queue hygiene in the proxy

Kernel tuning only buys time. If your reverse proxy runs with a worker connection limit of 1,024 and you are pushing 5,000 concurrent sockets, the kernel will happily accept them and the proxy will refuse to read them, producing the same timeout symptoms as a kernel-level drop.

Align three numbers before touching anything else: worker connections, the listen backlog in the server configuration, and the kernel’s somaxconn. When all three agree, connection spikes stop being an availability problem and become a capacity planning question.

Validate, then decide what to keep

Re-run the same load test after each change and compare p99 latency and retransmission rates, not just throughput. A tuning change that lifts requests per second by 8% but doubles tail latency is usually a bad trade for interactive workloads. Keep a short note in the repository describing each parameter, the measurement that motivated it, and the date it was reviewed. Six months later, when the application has changed, that note is the only thing that will tell you whether a value is still justified.

Finally, remember that sysctl tuning operates at the margins. It cannot compensate for a host with high steal time, a saturated disk, or a server placed far from its users. Treat it as the last 10% of performance work, applied after the architecture is right — and verify it with data every time. For further measurement-first kernel and networking walkthroughs, browse the tuning and benchmarking articles on virtualserversvps.com.

Leave a Reply