Scaling the Edge: High-Performance API Proxy Tuning with Nginx on CentOS 7
It starts with a few timeouts. Then the latency graph on your monitoring dashboard looks like a hockey stick. Finally, the dreaded 502 Bad Gateway errors start flooding your logs. If you are running a Service Oriented Architecture (SOA) or supporting a heavy mobile app backend, the default configurations on your Linux distribution are lying to you. They are tuned for general-purpose desktop usage, not for handling 10,000 concurrent connections per second.
I recently audited a setup for a client in Oslo whose e-commerce API was buckling under load. The code was fine. The database was optimized. But the Nginx reverse proxyâthe gateway to their entire infrastructureâwas choking on file descriptors. In this post, we are going to fix that.
The Bottleneck is Rarely CPU
In 2014, raw CPU power is cheap. The real killers of API performance are Context Switching, I/O Wait, and limits on open files. When you treat your VPS like a black box, you inherit the defaults of the underlying OS. On a standard CentOS 6 or the newly released CentOS 7, the system is often capped at 1,024 open files per process. For a busy API gateway, that is laughable.
We need to look at three layers: The Hardware, The Kernel, and The Application (Nginx).
1. The Hardware Reality: Spinning Disks are Dead
If you are serving API responses that require disk accessâeven just for logging access logs or reading static assetsâmechanical hard drives (HDDs) are your enemy. The seek time latency of 5-10ms adds up when you have hundreds of concurrent threads waiting on I/O.
Pro Tip: Turn off access logs during peak loads if you are not writing to an SSD. The blocking I/O on /var/log/nginx/access.log can bring a server to its knees faster than the actual traffic.
This is where infrastructure choice dictates success. At CoolVDS, we have moved exclusively to enterprise-grade SSD arrays. The difference in Random Read/Write performance is not just a metric; it is the difference between a 200ms response and a 20ms response. When hosting in Norway, you also want that hardware physically located here to minimize network latency to the Norwegian Internet Exchange (NIX).
2. Tuning the Linux Kernel
Before touching Nginx, we must tell the Linux kernel to allow more traffic. Open your /etc/sysctl.conf. We need to modify how the TCP stack behaves.
Warning: These settings are aggressive. Back up your config.
# /etc/sysctl.conf
# Increase system-wide file descriptor limit
fs.file-max = 2097152
# Increase the size of the receive queue.
net.core.netdev_max_backlog = 65536
net.core.somaxconn = 65536
# TCP memory tuning
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
# Increase ephemeral port range to prevent port exhaustion
net.ipv4.ip_local_port_range = 1024 65535
Apply these changes with:
sysctl -p
The net.ipv4.tcp_tw_reuse flag is critical. Without it, your server will run out of available sockets because they are stuck in the TIME_WAIT state, waiting for late packets that will never arrive.
3. Nginx Configuration for Concurrency
With the kernel unleashed, we configure Nginx (version 1.6.x or 1.7.x recommended). The default nginx.conf is too conservative.
Worker Processes and Connections
Set worker_processes to auto (or the number of CPU cores). The real magic happens in events.
worker_processes auto;
worker_rlimit_nofile 100000;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
worker_rlimit_nofile must be set here to override the user-level ulimit constraints specifically for the Nginx process.
Keepalive Upstreams
If you are proxying to a backend (like PHP-FPM, Node.js, or a Python WSGI server), you must use keepalive connections. Without this, Nginx opens and closes a new TCP connection to your backend for every single request. This adds unnecessary overhead.
http {
upstream backend_api {
server 127.0.0.1:8080;
keepalive 64;
}
server {
listen 80;
server_name api.example.no;
location / {
proxy_pass http://backend_api;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Buffering tweaks for JSON payloads
proxy_buffers 16 16k;
proxy_buffer_size 32k;
}
}
}
Note the proxy_set_header Connection "";. This is required to clear the "close" header that normally gets passed, allowing the persistent connection to the upstream to function correctly.
The "Noisy Neighbor" Problem in Virtualization
All the configuration in the world won't save you if your underlying virtualization technology is flawed. Many budget hosting providers use OpenVZ (container-based virtualization). In OpenVZ, you share the kernel with every other customer on the host node.
If another customer gets hit by a DDoS attack, the shared kernel's connection tracking table (conntrack) fills up, and your packets get dropped. This is unacceptable for a production API.
This is why CoolVDS utilizes KVM (Kernel-based Virtual Machine) technology. With KVM, you have your own isolated kernel. You can tune your own TCP stack (as we did above) without permission from the host, and a neighbor's heavy load cannot starve your kernel resources. For serious DevOps work, KVM is the industry standard.
Data Sovereignty and Latency
Since the Snowden revelations last year, the physical location of data has become a priority for European businesses. Hosting your API gateway inside Norwayâunder the jurisdiction of Datatilsynet rather than the US NSAâis a significant compliance advantage.
Furthermore, physics is undefeated. If your users are in Oslo, Bergen, or Trondheim, routing traffic through Frankfurt or London adds 20-40ms of latency round-trip. By deploying on a VPS Norway instance, you cut that network latency to near zero, ensuring your API feels instantaneous.
Summary of Optimization
| Setting | Default Value | Optimized Value | Impact |
|---|---|---|---|
| fs.file-max | ~100k | 2M+ | Prevents "Too many open files" |
| worker_connections | 512 | 4096+ | Higher concurrency per core |
| Keepalive | Off | On | Reduces TCP handshake overhead |
Final Thoughts
Performance is a feature. When your API responds in 50ms instead of 500ms, your mobile app feels native, and your conversion rates go up. Don't settle for default configs or oversold container hosting.
If you are ready to implement these changes on a platform that actually supports them, deploy a KVM instance today. High-performance SSD storage and local Norwegian peering come standard.
Need to test your new config? Deploy a CoolVDS instance in 55 seconds.