Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Linux Performance Tuning Basics

By Kokil Thapa | Last reviewed: September 2026

A slow Linux server rarely fails because one knob is wrong. It fails because nobody measured the bottleneck first. Linux performance tuning basics mean identifying whether CPU, memory, disk I/O, or network limits your workload, then applying targeted fixes at the kernel, service, and application layers. On production Linux system administration work I do for Laravel, WordPress, and eCommerce stacks, the same pattern repeats: measure, tune one layer, re-measure, document. This guide walks through that workflow with copy-paste commands you can run on Ubuntu 22/24 today.

What Is Linux Performance Tuning and When Should You Do It?

Performance tuning is the practice of adjusting operating system, middleware, and application settings so a server handles its real workload efficiently. You tune when response times climb, queue workers stall, or CPU and disk sit pegged during normal traffic—not because a blog post said to raise every limit to infinity.

Think in four resource domains: CPU, memory, disk I/O, and network. A Laravel booking app on Adventure Third Pole Trek might look CPU-bound during PDF generation but actually be disk-bound during log writes. Tuning the wrong layer wastes time and can make things worse.

Linux Performance Tuning WorkflowApplication WorkloadCPUtop, mpstatMemoryfree, vmstatDisk I/Oiostat, iotopNetworkss, nloadKernel Layersysctl, ulimits, schedulerService LayerPHP-FPM, MySQL, NginxRe-measure and Document
Linux performance tuning basics: measure four resource domains, then tune kernel and service layers before re-testing.

Signs you need tuning include sustained load average above CPU core count, swap usage climbing during business hours, disk await times above 20 ms on SSD, and TCP retransmits on ss -s. If none of those appear, your problem may live in application code or database queries—not the OS.

For deeper kernel work, read the companion guide on sysctl and ulimits tuning. For application-level gains, pair OS work with MySQL performance tuning and caching strategies.

How Do You Measure Linux Server Performance Before Tuning?

Never change production settings without a baseline snapshot. Capture metrics during peak traffic, not at 3 AM when the server is idle. A five-minute sample under real load tells you more than a week of idle monitoring.

Essential one-liner commands

Install sysstat if missing: apt install sysstat on Ubuntu. Then run these from an SSH session:

# CPU and run queue (1 sample per second, 10 times)
vmstat 1 10

# Per-CPU breakdown
mpstat -P ALL 1 5

# Memory and swap pressure
free -h
cat /proc/meminfo | grep -E '^(MemAvailable|SwapTotal|SwapFree):'

# Disk throughput and latency
iostat -xz 1 5

# Network sockets and retransmits
ss -s
ss -tan state time-wait | wc -l

# Top processes by CPU and memory
top -b -n 1 | head -20
ps aux --sort=-%mem | head -10

Interpret the numbers practically. On vmstat, a non-zero si/so swap column under load means memory pressure. On iostat, high %util with rising await points to disk saturation. On mpstat, one CPU at 100% while others idle suggests a single-threaded bottleneck.

Establish a baseline file

Save output to timestamped files under /var/log/baseline/. When a client reports slowness months later, you compare against a known-good state instead of guessing.

mkdir -p /var/log/baseline
DATE=$(date +%F-%H%M)
vmstat 1 10 > /var/log/baseline/vmstat-$DATE.txt
iostat -xz 1 5 > /var/log/baseline/iostat-$DATE.txt
free -h > /var/log/baseline/memory-$DATE.txt

For ongoing visibility, set up Netdata monitoring with alerts or at minimum a cron job that logs key metrics. Pair server metrics with application logs from your web application stack to correlate spikes with deploys or traffic events.

Which Linux Kernel and System Settings Improve Performance?

Kernel tuning through sysctl adjusts how Linux handles memory, networking, and file descriptors. Changes belong in /etc/sysctl.d/99-custom.conf, not scattered edits to /etc/sysctl.conf. Apply with sysctl --system and verify with sysctl -a | grep <param>.

Official reference: the Linux kernel sysctl documentation explains each parameter. Do not copy a random "ultimate sysctl" gist meant for 512 GB database servers onto a 4 GB VPS.

Sysctl Tuning LayersMemoryswappinessdirty_ratioNetworksomaxconntcp_fin_timeoutFile Limitsfile-maxinotify watches/etc/sysctl.d/99-custom.confApply: sysctl --systemWeb Server Stack BenefitsFewer dropped connections and smoother I/O
Sysctl groups for Linux performance tuning basics: memory, network, and file descriptor limits applied via drop-in config files.

Safe starting values for web servers

These values suit a typical 4–8 GB Ubuntu VPS running Nginx, PHP-FPM 8.3/8.4, and MySQL 8.4 or MySQL 9.7. Adjust upward only after measurement proves the need.

# /etc/sysctl.d/99-web-server.conf

# Reduce aggressive swap on web servers (default 60 is often too high)
vm.swappiness = 10

# Allow more queued connections for Nginx/Apache
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096

# Reuse TIME_WAIT sockets faster under high traffic
net.ipv4.tcp_fin_timeout = 15

# Increase system-wide open file limit ceiling
fs.file-max = 2097152

# Memory-mapped files for database workloads
vm.max_map_count = 262144

User limits with ulimit and systemd

Kernel limits mean nothing if the www-data user hits a 1024 file descriptor cap. Set limits in /etc/security/limits.d/99-web.conf:

www-data soft nofile 65535
www-data hard nofile 65535
mysql    soft nofile 65535
mysql    hard nofile 65535

PHP-FPM pools also declare rlimit_files in their pool config. After changes, restart affected services through systemd service management and confirm with cat /proc/$(pgrep -o php-fpm8.3)/limits | grep 'Max open files'.

More Ubuntu-specific tips appear in optimize Ubuntu server performance and speed up Ubuntu performance.

How Do You Tune PHP-FPM, MySQL, and the Web Server on Linux?

Application middleware consumes most resources on a typical LAMP or LEMP stack. OS tuning alone will not fix 200 PHP-FPM workers on a 2 GB server. Match process counts and buffer sizes to available RAM.

Before vs After Stack TuningBefore Tuningpm.max_children = 200Swap thrashing502 gateway errorsSlow query log silentAfter Tuningpm.max_children = 25Zero swap under loadStable response timesIndexes on hot queriesTuneRAM Budget FormulaAvailable RAM = Total - OS(500MB) - MySQL(25%) - Redis(128MB)max_children = Available / avg PHP process sizeMeasure process size: ps -ylC php-fpm8.3 --sort=rss
Linux performance tuning basics for PHP stacks: right-size FPM workers against measured RSS instead of guessing max_children.

PHP-FPM pool sizing

On PHP 8.3 or 8.5 with Laravel 12 or 13, a single worker often uses 40–80 MB RSS depending on packages loaded. Calculate:

  1. Check average RSS: ps -ylC php-fpm8.3 --sort=rss | tail -5
  2. Reserve 500 MB for OS and 25% of RAM for MySQL on shared hosts
  3. Set pm.max_children to fit the remainder
  4. Use pm = dynamic with sensible pm.start_servers and spare limits
; /etc/php/8.3/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 500
request_terminate_timeout = 60s

MySQL buffer and connection limits

On a dedicated database server with 8 GB RAM, start with innodb_buffer_pool_size = 5G. On a shared web+DB VPS, keep it under 40% of total RAM. Enable the slow query log and cross-reference with database indexing for performance.

# /etc/mysql/mysql.conf.d/mysqld.cnf
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
max_connections = 150
slow_query_log = 1
long_query_time = 1
innodb_flush_log_at_trx_commit = 2

For web-specific MySQL advice, see MySQL performance tuning for web applications.

Nginx vs Apache tuning

Your web server choice affects concurrency handling. Nginx excels at static files and reverse proxying. Apache with event MPM works well for mixed workloads. Compare both in Nginx vs Apache performance.

SettingNginx starting pointApache event MPMWhen to raise
Worker processesworker_processes auto;MaxRequestWorkers 150CPU cores underutilised at peak
Connectionsworker_connections 4096;ServerLimit 16ss -s shows dropped syns
Keepalivekeepalive_timeout 15;KeepAliveTimeout 5High TIME_WAIT counts
Gzipgzip on; gzip_types text/css application/json;mod_deflateLarge HTML/JSON payloads
Static cachingexpires 30d; on assetsExpiresActive OnRepeat asset requests dominate

Enable OPcache for PHP and Redis 8.10 for session and query caching where the application supports it. These layers often deliver bigger wins than any single sysctl change.

What Common Linux Performance Mistakes Should You Avoid?

The fastest way to destabilise a production server is to apply every tuning guide at once. I've recovered servers where someone disabled swap entirely, set vm.overcommit_memory = 1 without understanding Redis docs, and cranked PHP-FPM to 300 workers on 4 GB RAM—all in one afternoon.

Tuning Priority Decision TreeServer Slow?Measure baseline firstApp/query issue?Fix code and indexesResource saturated?Tune OS then servicesDeploy fix, re-measureDocument every changeNever skip backups before sysctl changes
Decision tree for Linux performance tuning basics: distinguish application bugs from resource saturation before changing kernel settings.
  • Tuning without measuring: You cannot optimise what you do not quantify. Always baseline first.
  • Disabling swap entirely: Swap is a safety valve. Lower swappiness instead of setting swap to zero on small VPS hosts.
  • Ignoring disk I/O: SSD await above 20 ms or HDD above 50 ms needs attention before adding CPU cores.
  • Skipping opcache after PHP upgrades: A PHP 8.3 to 8.5 migration without verifying OPcache settings leaves free performance on the table.
  • Running cron and backups at peak hours: Schedule heavy jobs off-peak. See automate database backups on Linux for safe timing patterns.
  • Never rebooting after kernel updates: Performance fixes in newer kernels require a reboot to take effect.

Process-level debugging belongs in Linux process management and signals. When tuning alone is not enough, professional speed optimization services and ongoing support and maintenance cover audit, fix, and monitor cycles.

Hosting costs on Nepali VPS plans often run Rs 1,500–5,000/month (~USD 11–37). Right-sizing through tuning beats upgrading hardware you do not need. Use the JSON formatter tool when parsing API monitoring payloads from external uptime services.

Key Takeaways

  • Measure CPU, memory, disk, and network with vmstat, iostat, and ss before changing any setting.
  • Apply sysctl and ulimits through drop-in config files, then restart services and verify limits with /proc/PID/limits.
  • Size PHP-FPM max_children from measured RSS, not guesswork—swap thrashing means you overshot.
  • Allocate MySQL innodb_buffer_pool_size to fit your RAM budget; index slow queries separately.
  • Document every change with timestamps so you can roll back during the next traffic spike.
  • Re-measure after each tuning layer; stop when metrics meet your SLA instead of chasing perfect benchmark scores.

People Also Ask

What is the first step in Linux performance tuning?

Establish a baseline under normal and peak load using vmstat, iostat, free, and ss. Save the output to dated files. Without a baseline, you cannot tell whether a change helped or hurt.

Does disabling swap improve Linux performance?

Usually no. Disabling swap on a memory-constrained VPS causes OOM kills instead of graceful degradation. Lower vm.swappiness to 10 on web servers so the kernel prefers keeping application pages in RAM.

How much RAM should innodb_buffer_pool_size use?

On a dedicated MySQL server, allocate 60–70% of total RAM. On a shared web+database VPS, stay near 25–40% so PHP-FPM and the OS retain enough headroom. Always leave at least 500 MB free for the kernel.

When should you upgrade hardware instead of tuning?

Upgrade when all sensible tuning is done and metrics still exceed your SLA—sustained CPU above 80% with optimised code, disk utilisation above 80% on SSD, or memory pressure after right-sizing every service. Tuning cannot fix fundamentally undersized infrastructure.

Apply Linux Performance Tuning Basics on Your Stack

Strong Linux performance tuning basics come down to a repeatable cycle: measure, identify the bottleneck layer, change one thing, re-measure, document. That workflow has kept Laravel legal-tech portals, WooCommerce florists, and shared EC2 deploy targets stable through Dashain traffic spikes and quiet weekday nights alike. Start with the commands in this guide on your staging server first. When you need hands-on help across kernel, PHP-FPM, MySQL, and testing and optimization, review the Notary Nepal portfolio and other production work on the portfolio page. For a full audit of your production environment, contact us or explore about me to see how Kokil Thapa approaches server work alongside application delivery.

Frequently Asked Questions

Establish a baseline under normal and peak load using vmstat, iostat, free, and ss. Save dated output to files such as /var/log/baseline/ before changing any setting.

Linux performance tuning adjusts operating system, middleware, and application settings so a server handles its real workload efficiently. You tune when response times climb, queue workers stall, or CPU and disk stay pegged during normal traffic—not preemptively. Think in four resource domains: CPU, memory, disk I/O, and network. On production Laravel and WordPress stacks I maintain, the same pattern repeats: a booking app may look CPU-bound during PDF generation but actually be disk-bound during log writes. Tuning the wrong layer wastes time and can make things worse.

Install sysstat with apt install sysstat on Ubuntu 22/24, then capture a five-minute sample during peak traffic. Run vmstat 1 10 for CPU and run queue, mpstat -P ALL 1 5 for per-CPU breakdown, free -h and /proc/meminfo for memory pressure, iostat -xz 1 5 for disk throughput and latency, ss -s for network retransmits, and top or ps aux --sort=-%mem for top processes. Save all output to timestamped files under /var/log/baseline/ so you can compare months later when a client reports slowness.

Watch for sustained load average above your CPU core count, swap usage climbing during business hours, disk await times above 20 ms on SSD or above 50 ms on HDD, and TCP retransmits visible in ss -s output. On vmstat, non-zero si/so swap columns under load mean memory pressure. On iostat, high %util with rising await points to disk saturation. On mpstat, one CPU at 100% while others idle suggests a single-threaded bottleneck. If none of these appear, the problem likely lives in application code or database queries—not the OS.

Usually no. Disabling swap on a memory-constrained VPS causes OOM kills instead of graceful degradation. Lower vm.swappiness to 10 on web servers so the kernel prefers keeping application pages in RAM.

On a dedicated MySQL server, allocate 60–70% of total RAM. On a shared web+database VPS, stay near 25–40% so PHP-FPM and the OS retain enough headroom.

Place kernel tuning in /etc/sysctl.d/99-web-server.conf, not scattered edits to /etc/sysctl.conf, then apply with sysctl --system. Safe starting values for a typical 4–8 GB Ubuntu VPS running Nginx or Apache with PHP-FPM 8.3/8.4 and MySQL include vm.swappiness = 10, net.core.somaxconn = 4096, net.ipv4.tcp_max_syn_backlog = 4096, net.ipv4.tcp_fin_timeout = 15, fs.file-max = 2097152, and vm.max_map_count = 262144. Do not copy random sysctl gists meant for 512 GB database servers onto a 4 GB VPS. Adjust upward only after measurement proves the need.

Never guess worker counts. On PHP 8.3 or 8.5 with Laravel 12 or 13, a single worker often uses 40–80 MB RSS depending on packages loaded. Check average RSS with ps -ylC php-fpm8.3 --sort=rss, reserve 500 MB for the OS and 25% of RAM for MySQL on shared hosts, then set pm.max_children to fit the remainder. Use pm = dynamic with sensible pm.start_servers and spare limits. If swap thrashing appears after changes, you overshot. OS tuning alone will not fix 200 PHP-FPM workers on a 2 GB server.

Match buffer sizes to available RAM rather than copying dedicated-server configs. On a shared web+DB VPS, keep innodb_buffer_pool_size under 40% of total RAM—for example 2G on a smaller host—while leaving at least 500 MB free for the kernel. Enable slow_query_log with long_query_time = 1 to catch query problems separately from buffer tuning. Set innodb_flush_log_at_trx_commit = 2 for a reasonable durability-performance trade-off on web workloads. On a dedicated 8 GB database server, innodb_buffer_pool_size = 5G is a sensible starting point.

The fastest way to destabilise production is applying every tuning guide at once. I've recovered servers where someone disabled swap entirely, set vm.overcommit_memory = 1 without understanding Redis docs, and cranked PHP-FPM to 300 workers on 4 GB RAM in one afternoon. Other recurring mistakes: tuning without a baseline, ignoring disk I/O before adding CPU cores, skipping OPcache verification after PHP upgrades, running cron and backups at peak hours, and never rebooting after kernel updates that contain performance fixes. Change one layer, re-measure, and document every adjustment with timestamps.

Upgrade when all sensible tuning is done and metrics still exceed your SLA—sustained CPU above 80% with optimised code, disk utilisation above 80% on SSD, or memory pressure after right-sizing every service. Tuning cannot fix fundamentally undersized infrastructure. On Nepali VPS plans running Rs 1,500–5,000/month (~USD 11–37), right-sizing PHP-FPM pools, MySQL buffers, and sysctl values often beats paying for hardware you do not actually need. Treat hardware upgrades as the step after measure-tune-re-measure cycles fail, not the first reaction to slow response times.

Kernel sysctl limits mean nothing if the www-data user hits a 1024 file descriptor cap. Set per-user limits in /etc/security/limits.d/99-web.conf with soft and hard nofile values of 65535 for www-data and mysql. PHP-FPM pools should also declare rlimit_files in their pool config. After changes, restart affected services through systemd and confirm with cat /proc/$(pgrep -o php-fpm8.3)/limits | grep 'Max open files'. Pair this with fs.file-max = 2097152 in your sysctl drop-in so system-wide ceilings stay above per-process needs under high-traffic Nginx or Apache workloads.

Your web server choice affects concurrency handling. Nginx excels at static files and reverse proxying; Apache with event MPM works well for mixed workloads. Starting points from the article: set Nginx worker_processes auto and worker_connections 4096, or Apache MaxRequestWorkers 150 and ServerLimit 16. Raise worker counts only when CPU cores sit underutilised at peak. Shorten keepalive_timeout to 15 on Nginx or KeepAliveTimeout to 5 on Apache when ss -s shows high TIME_WAIT counts. Enable gzip or mod_deflate for large HTML and JSON payloads, and set static asset caching with expires or ExpiresActive for repeat requests.

Application-layer caching often delivers bigger wins than any single sysctl change. Enable OPcache for PHP after every upgrade—skipping verification after a PHP 8.3 to 8.5 migration leaves free performance on the table. Use Redis 8.10 for session and query caching where your Laravel, WordPress, or eCommerce application supports it. These middleware layers sit above kernel tuning and below application code fixes. Pair them with right-sized PHP-FPM pools and MySQL innodb_buffer_pool_size rather than treating them as replacements for measuring CPU, memory, disk, and network bottlenecks first.

Save baseline snapshots to timestamped files under /var/log/baseline/ using vmstat, iostat, and free output before any change. Document every sysctl, ulimit, PHP-FPM, and MySQL adjustment with timestamps so you can roll back during the next traffic spike. For ongoing visibility, set up Netdata monitoring with alerts or at minimum a cron job that logs key metrics. Pair server metrics with application logs from your web stack to correlate spikes with deploys or traffic events. Re-measure after each tuning layer and stop when metrics meet your SLA instead of chasing perfect benchmark scores.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: