sysctl reads and changes kernel parameters at runtime: network buffers, memory behaviour, IP forwarding and hundreds more. A few of them really do make a difference on servers. Most “ultimate sysctl.conf” lists copied from the internet don’t, and some make things worse. This guide covers the mechanics and the settings worth knowing.
On a KVM VPS (like all VPS.DO VPS plans) you run your own kernel, so you can change these freely. Container-based virtualization often blocks them.
Read and set values
sysctl net.core.somaxconn # read one
sysctl -a | grep swappiness # search
sudo sysctl -w vm.swappiness=10 # set now (lost at reboot)
The same values appear as files under /proc/sys/ (dots become slashes): cat /proc/sys/vm/swappiness.
Make changes persistent
Put settings in a file under /etc/sysctl.d/:
sudo tee /etc/sysctl.d/99-custom.conf > /dev/null <<'EOF'
vm.swappiness = 10
net.core.somaxconn = 4096
EOF
sudo sysctl --system # load all sysctl files now
Files are applied in lexical order, so 99- wins over earlier ones. Don’t edit /etc/sysctl.conf directly on distributions that ship it as a package file. Your own file in sysctl.d survives upgrades and is easy to find.
Settings worth knowing
Memory
vm.swappiness = 10
This controls how eagerly the kernel swaps out application memory rather than dropping file cache (default 60). On servers with databases or app processes, 10 keeps the working set in RAM longer. See swap usage.
vm.overcommit_memory = 1
Redis recommends this so background saves (which fork) don’t fail. Only set it if you run Redis and understand that it disables the kernel’s allocation heuristics.
TCP congestion control: BBR
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
BBR (from Google) often improves throughput on long-distance and lossy paths, such as serving users far away or across the Pacific. It’s one of the few changes with a clearly visible benefit for web and download servers. Check it’s available, then verify:
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
Connection backlog
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
somaxconn caps the listen queue for accepting connections. Modern kernels (5.4+) default to 4096 already. Raise it for very busy servers. The application must request a big backlog too (Nginx listen 443 ssl backlog=4096;).
Port range for many outgoing connections
net.ipv4.ip_local_port_range = 10240 65535
Proxies and apps making many outbound connections (to upstreams or APIs) can run out of ephemeral ports. Keepalive connections to upstreams are the better fix. See Nginx load balancing.
Connection tracking
net.netfilter.nf_conntrack_max = 262144
If dmesg shows nf_conntrack: table full, dropping packet, the firewall’s connection tracking table is too small for your traffic. That’s common on busy servers using iptables, nftables or UFW. See dmesg.
IP forwarding (VPN, routers, containers)
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
This is required for WireGuard or OpenVPN gateways and NAT. Docker enables it itself. See WireGuard.
Security-related defaults
net.ipv4.tcp_syncookies = 1 # SYN flood resilience (usually already on)
net.ipv4.conf.all.rp_filter = 1 # drop spoofed source addresses
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
Most are already set by distribution defaults. Verify them as part of hardening. See Linux server hardening.
File handles and inotify
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
max_user_watches matters for file watchers (Syncthing, IDE servers, some build tools) that report “ENOSPC: System limit for number of file watchers reached”. Per-process open-file limits are set elsewhere. See ulimit.
What to avoid
net.ipv4.tcp_tw_recycle— removed from the kernel because it broke clients behind NAT. Copy-pasted configs still include it and produce errors.- Huge buffer sizes (
rmem_max/wmem_maxat hundreds of MB) “for speed”: modern kernels auto-tune buffers. Increase them only for measured high-bandwidth, high-latency transfers. vm.swappiness = 0as a cure-all: it can make the OOM killer act sooner. 10 is a gentler choice.- Applying dozens of settings at once: change one thing, measure, keep it if it helps.
Verify after reboot
sudo sysctl --system | grep -i error
sysctl vm.swappiness net.ipv4.tcp_congestion_control
Some keys only exist once a module is loaded. nf_conntrack_max needs the nf_conntrack module, so it may be applied too early at boot. Add the module to /etc/modules-load.d/ if needed.
Quick reference
| Task | Command |
|---|---|
| Read | sysctl key |
| Set temporarily | sudo sysctl -w key=value |
| Persistent | file in /etc/sysctl.d/99-custom.conf |
| Reload all | sudo sysctl --system |
| Enable BBR | default_qdisc=fq + tcp_congestion_control=bbr |
| Lower swapping | vm.swappiness=10 |
| Forwarding | net.ipv4.ip_forward=1 |
Related: load average and VPS speed optimization.