I have been running Nginx on a 1 vCPU / 2 GB RAM VPS for a while now. These are my notes on configuration choices that make sense at this scale.
The defaults are mostly fine
Nginx is efficient out of the box. For a small site serving static files, you can run the default configuration and it will handle far more traffic than your server will ever see. But there are a few things worth adjusting.
Worker processes
The worker_processes directive controls how many worker processes Nginx spawns. The common advice is to set it to the number of CPU cores:
worker_processes auto;
The auto value does exactly that. On a 1 vCPU machine, this gives you one worker, which is appropriate. There is no benefit to running multiple workers on a single core.
Each worker can handle thousands of concurrent connections, so one worker is not a bottleneck for a small site.
Worker connections
events {
worker_connections 512;
}
The default is often 768 or 1024. For a small personal server, 512 is more than enough. Each connection uses a small amount of memory, so there is no harm in keeping this reasonable.
The maximum number of simultaneous connections your server can handle is worker_processes * worker_connections. With 1 worker and 512 connections, that is 512 concurrent connections. For a personal blog, you will never come close.
Gzip compression
Enabling gzip reduces the size of text-based responses significantly:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
A few notes on these settings:
gzip_comp_level 4is a good balance between compression ratio and CPU usage. Level 6 or higher uses noticeably more CPU with diminishing returns.gzip_min_length 256avoids compressing tiny responses where the overhead is not worth it.gzip_vary onensures caches handle compressed and uncompressed versions correctly.
Static file caching
For a static site, telling browsers to cache assets saves bandwidth and makes repeat visits faster:
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
HTML files should not be cached as aggressively, since you want updates to appear immediately:
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, no-transform";
}
Logging
The default access log writes every request to disk. On a small VPS with an SSD, this is fine for low traffic. But if you want to reduce disk writes, you can buffer the logs:
access_log /var/log/nginx/access.log combined buffer=16k flush=5m;
This buffers log entries and writes them in batches. The flush=5m ensures logs are written at least every five minutes even if the buffer is not full.
For a personal site with minimal traffic, I actually keep the default logging. The disk I/O is negligible. But if you are running something busier, buffered logging helps.
Security headers
A few headers that are worth adding to every response:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
These are low-effort, high-value. They prevent content type sniffing, clickjacking, and excessive referrer information leakage.
Disabling server tokens
By default Nginx includes its version number in error pages and the Server response header. Disabling this reveals less information:
server_tokens off;
This goes in the http block of your main Nginx configuration.
Putting it together
Here is a condensed version of my Nginx configuration for reference:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 512;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
server_tokens off;
keepalive_timeout 65;
gzip on;
gzip_vary on;
gzip_comp_level 4;
gzip_min_length 256;
gzip_types text/plain text/css text/javascript
application/javascript application/json
application/xml image/svg+xml;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
The site-specific server block lives in /etc/nginx/sites-available/ and is symlinked to sites-enabled/.
Monitoring
I keep an eye on Nginx with a few simple commands:
# Check active connections
curl -s http://127.0.0.1/nginx_status
# Watch the access log
tail -f /var/log/nginx/access.log
# Test configuration before reloading
nginx -t && systemctl reload nginx
The nginx_status endpoint requires the stub_status module, which is included in most Nginx packages. Add it to a server block restricted to localhost:
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
Resource usage
On my server, Nginx uses about 3 MB of RAM for the master process and 5 MB per worker. With one worker, that is roughly 8 MB total. CPU usage for serving static files is effectively zero under normal load.
For a small VPS, Nginx is hard to beat. It does its job quietly and stays out of the way. The Nginx documentation is thorough if you need to dig deeper into any of these settings.