Nginx Reverse Proxy on a KVM VPS: Upstream Buffers, SSL & WebSocket Setup

A complete configuration reference for deploying Nginx as a high-performance reverse proxy on a Linux KVM VPS, covering buffer tuning, header forwarding, and SSL.

Deploying Nginx as a front-end reverse proxy on a Linux KVM VPS is standard engineering practice for modern web architectures. By placing Nginx in front of application runtimes such as Node.js, Python ASGI/WSGI servers, Go binaries, or Docker containers, engineering teams offload TLS termination, enforce HTTP header hygiene, buffer slow client connections, and protect backend application processes from memory starvation.

Role of the Reverse Proxy in Production Workloads

Directly exposing application servers (such as Uvicorn, Gunicorn, Puma, or Node.js) to the public internet introduces operational risks. Application runtimes are optimized for request execution rather than high-concurrency connection management. Slow client connections, large file uploads, and TLS handshakes consume valuable worker threads, reducing the application's overall throughput.

Nginx solves this by leveraging an asynchronous, event-driven architecture based on Linux epoll. A single Nginx worker process can maintain thousands of concurrent client connections, buffering incoming requests and feeding them to local upstream application sockets only when the complete payload has been received.

Core Reverse Proxy Directives and Header Management

The foundation of reverse proxying in Nginx is the ngx_http_proxy_module. When passing requests to an upstream server, Nginx must modify specific request headers to ensure the application retains awareness of the original client's network identity.

Consider the standard proxy configuration below:

server {
    listen 80;
    server_name api.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;

        # Forward real client connection metadata
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeout configurations
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

Header Inheritance Warning

In Nginx, proxy_set_header directives are inherited from parent blocks (such as the http or server context) only if no proxy_set_header directives are defined in the current location block. If you define a single proxy_set_header inside a location, all parent-level header directives are discarded for that location. Always verify that all required identity headers are explicitly specified in the active block.

Tuning Upstream Buffers to Prevent Disk Thrashing

By default, Nginx buffers responses received from upstream servers. When an application generates a response, Nginx saves it into internal memory buffers, allowing the backend worker to finish immediately and return to processing other requests while Nginx streams the content to the client.

However, if the upstream response exceeds Nginx's allocated memory buffers, Nginx writes the remaining response to a temporary file on disk (proxy_temp_path). On high-traffic systems, excessive disk buffering degrades I/O performance. To optimize buffer allocations for high-throughput APIs, tune buffer directives inside your location or server block:

# Enable response buffering
proxy_buffering on;

# Size of the buffer used for reading the first part of the response (headers)
proxy_buffer_size 8k;

# Number and size of buffers for the response body
proxy_buffers 8 64k;

# Maximum size of buffers that can be busy sending responses while continuing to read
proxy_busy_buffers_size 128k;

# Limit size of data written to disk temp file at once
proxy_temp_file_write_size 128k;

For systems handling large JSON payloads or multi-megabyte API outputs, increasing proxy_buffers ensures data stays entirely in RAM, taking full advantage of KVM virtual memory allocations.

Rate Limiting and Connection Throttling

To defend backend services against abusive scrapers and Denial of Service (DoS) attacks, configure rate limiting directly within Nginx before requests reach the application runtime. Nginx uses the leaky bucket algorithm to enforce steady request flow:

# Inside the http {} block:
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr_limit:10m;

# Inside the location / block:
limit_req zone=api_limit burst=20 nodelay;
limit_conn addr_limit 10;

Here, each unique IP address is allocated space in a 10-megabyte shared memory zone, tracking requests at a baseline rate of 10 requests per second. The burst=20 nodelay parameter allows short bursts of legitimate browsing activity while immediately serving HTTP 503 Service Unavailable to requests exceeding the threshold, protecting upstream Python or Node.js workers from thread starvation.

Enabling WebSocket Support

Modern interactive applications, real-time telemetry dashboards, and chat backends rely on WebSockets. Because WebSockets initiate as standard HTTP requests before performing a protocol upgrade, Nginx requires explicit hop-by-hop header forwarding to maintain persistent two-way tunnels:

location /ws/ {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;

    # Pass hop-by-hop Upgrade headers
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;

    # Extend timeouts for persistent real-time connections
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

Setting proxy_read_timeout to an extended interval (such as 3600 seconds) prevents Nginx from severing idle WebSocket connections when clients send heartbeats at wide intervals.

Deploying on StreamData Cloud Infrastructure

Running high-performance Nginx reverse proxies requires fast CPU clock speeds and low storage latency for access logging and static file caching. StreamData Networks provides high-speed KVM VPS instances equipped with RAID NVMe storage, 1 Gbps and 10 Gbps port options where available, and deployment availability across physical nodes in Mumbai, Noida, and Jaipur.

Deploy cloud instances on StreamData KVM VPS, evaluate enterprise bare-metal options on StreamData Dedicated Servers, or explore company infrastructure via StreamData Company.


Sources