Nginx Tuning for a Small VPS: Worker Processes, Buffers, and Timeouts That Matter

On a 1–2 vCPU, 1–2 GB VPS, the default nginx configuration wastes memory and lets slow clients tie up workers that should be serving real traffic. The good news: a handful of directives fixes most of the pain, and every change is verifiable with a benchmark. This guide walks through the nginx settings that matter on small servers — worker processes, timeouts, buffers, and static-file handling — with concrete values and the reasoning behind them.

Worker Processes and Connections

nginx runs one worker process per CPU core by design. On a small VPS, set worker_processes auto; so nginx matches whatever vCPUs the kernel actually sees — including your burst allocation. Each worker handles up to worker_connections simultaneous connections; 1024 is a sensible ceiling on a 1–2 GB box. The event loop should look like this:

  • worker_processes auto; — one worker per vCPU
  • worker_connections 1024; — connections per worker (2048 only if RAM allows)
  • use epoll; — the right event model on Linux
  • multi_accept on; — accept all new connections in one notification

Memory math is simple: each connection costs a few kilobytes of overhead, and each worker’s total memory footprint scales with worker_connections. On a 1 GB VPS, raising worker_connections to 4096 without raising RAM just moves the problem from nginx to the OOM killer.

Timeouts That Stop Slow Clients from Hogging Workers

Slow clients — mobile connections, crawlers, keep-alive hoarders — occupy a worker for as long as the timeouts allow. Tight, realistic values free workers quickly without hurting legitimate users:

  • keepalive_timeout 20; — how long an idle keep-alive connection stays open (20–30 s is plenty)
  • keepalive_requests 500; — requests per keep-alive connection before recycling
  • client_body_timeout 10; — seconds to read the request body (10–15 s)
  • client_header_timeout 10; — seconds to read the request headers
  • send_timeout 10; — seconds between two write operations to a client

These values assume your application responds in well under a second. If your PHP or Node backend regularly takes longer, raise send_timeout to 30–60 s — but first fix the backend, because timeouts are a symptom, not a solution.

Buffers and Request Sizes

  • client_body_buffer_size 16k; — buffer for the request body before spilling to disk
  • client_max_body_size 2m; — maximum upload size; raise it only if your app needs it
  • large_client_header_buffers 4 16k; — headroom for large cookies and long URIs

Oversized buffers on a small VPS are pure waste — nginx allocates them per request. Keep them small and let the OS page cache do the heavy lifting.

Static Files and Compression

For static assets, the classic trio is sendfile on; (copy files straight from disk to the socket), tcp_nopush on; (send headers and file data in one packet), and tcp_nodelay on; (disable Nagle for interactive traffic). Enable gzip for text assets with gzip on;, gzip_comp_level 5;, gzip_min_length 1024;, and gzip_types text/css application/javascript application/json image/svg+xml;. Finally, cache open file metadata so repeated requests skip stat calls: open_file_cache max=1000 inactive=20s;, open_file_cache_valid 30s;, open_file_cache_min_uses 2;.

DirectiveRecommended valueWhy it matters
worker_processesautoMatches workers to actual vCPUs
keepalive_timeout20Frees workers held by idle connections
client_max_body_size2mPrevents memory waste on oversized uploads
gzip_comp_level5Good compression without burning CPU
open_file_cachemax=1000 inactive=20sCuts stat() syscalls for repeated files

Small Defaults Worth Changing

A few one-line defaults round out the setup. Set server_tokens off; to stop nginx from advertising its version in headers — a cheap win that also reduces automated exploit attempts. Replace the default combined log format with a minimal one and disable access logging for static assets: location ~* \.(css|js|png|jpg|svg|woff2)$ { access_log off; expires 7d; } keeps disk I/O and log rotation down on small boxes. If you proxy to PHP-FPM or an upstream app, add upstream php { server unix:/run/php/php-fpm.sock; keepalive 32; } and set proxy_http_version 1.1; with proxy_set_header Connection ""; so upstream connections are reused instead of re-established per request — a measurable latency win under concurrent load.

Verify and Measure

After editing, validate and reload with nginx -t && sudo systemctl reload nginx. Then benchmark before and after with wrk: wrk -t2 -c50 -d30s http://localhost/. On a typical small VPS you should see lower p95 latency and a smaller nginx memory footprint after tuning. The changes interact with your PHP-FPM or application settings, so retest after any backend change. Track resident memory too — ps -o pid,rss,cmd -C nginx shows per-worker RSS, and each worker should stay well under 50 MB on a tuned config; if workers creep toward 100 MB, reduce worker_connections or trim buffer sizes. If your workload is WordPress-heavy, also look at the caching features compared at virtualserversvps.com — nginx tuning pairs well with FastCGI caching and Redis object caching. The FAQ also answers common questions about running web servers on small plans.

Start with the timeouts and buffer sizes — they are the highest-impact, lowest-risk changes on a small VPS. Compare VPS plans sized for nginx and PHP-FPM and deploy your tuned stack today.

Leave a Reply