Random tuning tips from the internet rarely help. A repeatable method does: measure, find the bottleneck, fix that one thing, measure again. This guide follows that approach for a typical Linux web or application server.

1. Start with the symptom

Define what “slow” means in numbers: page response time, API latency, job duration, requests per second. Measure it before changing anything:

curl -o /dev/null -s -w 'connect %{time_connect}s, ttfb %{time_starttransfer}s, total %{time_total}s\n' https://example.com/

2. Check resources with the USE method

For every resource, check Utilization, Saturation and Errors:

Resource Utilization Saturation Errors
CPU mpstat -P ALL 1 load average vs nproc, run queue (vmstat r) —
Memory free -h (available) swapping (vmstat si/so), OOM kills journalctl -k | grep -i oom
Disk iostat -xz 1 (%util) aqu-sz, high await dmesg | grep -i error
Network sar -n DEV 1 dropped packets, retransmits (nstat) ip -s link

Pressure stall information summarizes saturation neatly:

cat /proc/pressure/{cpu,memory,io}

3. Fix the bottleneck you found

CPU-bound

  • Find the process: top, pidstat 1.
  • Profile the application (slow code paths, heavy regex, missing caching).
  • For web apps, cache rendered pages so most requests skip application code.
  • Check %st (steal) in top on a VPS — high steal means the host is busy; consider a larger plan.

Memory-bound

  • Reduce worker counts so everything fits in RAM (PHP-FPM, Gunicorn, Node cluster workers).
  • Find memory hogs: ps aux --sort=-rss | head.
  • Add swap as a safety net, not a solution — see swap file vs partition.

Disk-bound

  • Identify the writer/reader with iotop.
  • Give databases enough buffer memory, add Redis caching, reduce logging.
  • Details: Linux disk performance.

Network-bound

  • Enable compression (gzip/Brotli) and HTTP/2 or HTTP/3.
  • Use a CDN for static files — see VPS + Cloudflare.
  • Enable BBR congestion control for distant users.
  • Check bandwidth limits: VPS bandwidth explained.

4. Tune the services

Most real-world wins come from service configuration rather than the kernel:

  • Nginx: worker_processes auto, enough worker_connections, keepalive, static file caching, open_file_cache.
  • PHP-FPM: OPcache on, pm.max_children sized to RAM.
  • MariaDB/MySQL: innodb_buffer_pool_size, slow query log, indexes on filtered columns.
  • PostgreSQL: shared_buffers, effective_cache_size, work_mem; use EXPLAIN ANALYZE on slow queries.

5. Kernel and system settings (when needed)

Only after the above, and only for the bottleneck you see:

# /etc/sysctl.d/90-perf.conf
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.ip_local_port_range = 10240 65535
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
vm.swappiness = 10

Raise file-descriptor limits for busy services (LimitNOFILE in a systemd override). More in Debian performance tuning.

6. Measure again — and keep measuring

Repeat your original measurement. Keep long-term monitoring (Netdata, Prometheus + node_exporter + Grafana) so you can see trends and correlate slowdowns with deploys or traffic.

7. Know when to scale

Tuning has limits. Scale up when resources are consistently above ~70% at normal peak load after optimization. Options:

  • Vertical: more vCPU/RAM — our KVM VPS plans can be upgraded by ticket.
  • Horizontal: separate the database onto its own server, add a load balancer and more app servers.
  • Dedicated hardware for consistently heavy workloads — see dedicated servers.

Summary

Measure the symptom, find the saturated resource, fix that, and measure again. Most gains come from caching and service configuration; kernel tuning is the finishing touch.

  • Linux
  • Performance