Linux kernel parameters control how your system allocates resources, handles network connections, and manages memory. On RHEL 8, the sysctl utility provides a clean interface for reading and writing these parameters at runtime, while drop-in configuration files under /etc/sysctl.d/ make changes persistent across reboots. Properly tuned kernel parameters can significantly improve throughput, reduce latency, and stabilize busy production servers. This tutorial walks through the most impactful tunables for networking, file descriptors, and virtual memory.
Prerequisites
- A running RHEL 8 system with root or
sudoaccess - Basic familiarity with the Linux command line and text editors such as
viornano - An understanding of the workload you intend to tune (web server, database, general-purpose)
Step 1 — Create a Custom sysctl Drop-in File
Rather than editing /etc/sysctl.conf directly, place your customizations in a dedicated file under /etc/sysctl.d/. Files are processed in lexicographic order, so naming yours 99-custom.conf ensures it is applied last and overrides any distribution defaults.
sudo touch /etc/sysctl.d/99-custom.conf
sudo chmod 644 /etc/sysctl.d/99-custom.conf
Step 2 — Tune Network Stack Parameters
High-traffic servers benefit from larger connection queues and faster socket teardown. The following parameters increase the maximum number of pending connections, reduce TIME_WAIT lingering, and expand socket receive and send buffers for improved throughput.
sudo tee /etc/sysctl.d/99-custom.conf > /dev/null <<'EOF'
# Network tuning
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 15
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
EOF
net.core.somaxconn sets the maximum length of the accept queue for listening sockets. tcp_max_syn_backlog controls the incomplete connection queue. Reducing tcp_fin_timeout to 15 seconds frees TIME_WAIT sockets more quickly under heavy load. The rmem_max and wmem_max values expand the maximum socket buffer sizes to 128 MB, which is important for high-bandwidth or high-latency links.
Step 3 — Increase the System-Wide File Descriptor Limit
Web servers, databases, and message brokers routinely open thousands of simultaneous file descriptors. The kernel-level ceiling is set via fs.file-max, while per-process limits are controlled through PAM limits.
# Append to /etc/sysctl.d/99-custom.conf
echo "fs.file-max = 2097152" | sudo tee -a /etc/sysctl.d/99-custom.conf
# Set per-process limits for all users
sudo tee /etc/security/limits.d/99-nofile.conf > /dev/null <<'EOF'
* soft nofile 1048576
* hard nofile 1048576
root soft nofile 1048576
root hard nofile 1048576
EOF
The /etc/security/limits.d/ file is processed by the PAM pam_limits module when a user logs in or a service starts. Both soft and hard limits must be raised; many applications only check the hard limit when increasing their own soft limit at startup.
Step 4 — Configure Virtual Memory Tunables
The VM subsystem parameters govern how aggressively the kernel swaps memory to disk and how much dirty data accumulates before a write-back flush. For latency-sensitive workloads, reduce swappiness and tighten the dirty ratio thresholds.
# Append VM tunables to the custom conf
sudo tee -a /etc/sysctl.d/99-custom.conf > /dev/null <<'EOF'
# Virtual memory tuning
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.overcommit_memory = 1
EOF
Setting vm.swappiness = 10 tells the kernel to strongly prefer keeping processes in RAM over evicting pages to swap. vm.dirty_ratio = 15 means the kernel will start a synchronous write-back flush when 15% of available memory holds dirty pages, preventing sudden large I/O stalls. vm.dirty_background_ratio = 5 starts background write-back earlier, smoothing out I/O over time.
Step 5 — Apply All Parameters Without Rebooting
The sysctl --system command reads all configuration files from /etc/sysctl.d/, /run/sysctl.d/, and /usr/lib/sysctl.d/ in order and applies every parameter. This lets you activate changes immediately without a reboot.
# Apply all sysctl drop-in files
sudo sysctl --system
# Verify specific values were applied
sysctl net.core.somaxconn
sysctl vm.swappiness
sysctl fs.file-max
# Verify file descriptor limits for the current session
ulimit -n
Step 6 — Verify Persistence After Reboot
Confirm the configuration survives a reboot by checking that sysctl.d files are loaded at boot time and inspecting the applied values after restarting.
# Check that the drop-in file is valid
sudo sysctl -p /etc/sysctl.d/99-custom.conf
# After a reboot, verify key values
sysctl -a | grep -E "somaxconn|swappiness|file-max|dirty_ratio"
# Check current open file descriptor counts system-wide
cat /proc/sys/fs/file-nr
The /proc/sys/fs/file-nr file shows three numbers: allocated file handles, free file handles, and the maximum (fs.file-max). If the first number approaches the third, increase fs.file-max further.
Conclusion
You have configured persistent kernel parameter tuning on RHEL 8 using /etc/sysctl.d/99-custom.conf. The network stack can now handle tens of thousands of concurrent connections, per-process file descriptor limits have been raised to one million, and the virtual memory subsystem is tuned to minimize swap usage and smooth out I/O. Always benchmark before and after changes using tools like netstat, ss, or sar to confirm that tunables produce the expected improvement for your specific workload.
Next steps: How to Profile Application Performance with perf on RHEL 8, How to Configure Huge Pages for Database Performance on RHEL 8, and How to Monitor System Performance with sar and sysstat on RHEL 8.