Most Nginx installation guides tell you the basics——install it via apt-get, tweak a few lines of config here and there, and voilà, you have a web server. And, in most cases, a conventional Nginx installation will serve your site just fine.

However, if you truly want to squeeze every bit of performance out of Nginx, you must go deeper. In this guide, I’ll explain which Nginx settings can be fine-tuned to optimize performance when handling large numbers of clients. One thing to note: this is not a comprehensive tuning guide. It’s a simple preview——an overview of settings that can be tweaked to improve performance. Your situation may vary.
Basic (Optimized) Configuration
The only file we will modify is nginx.conf, which contains all the settings for Nginx’s various modules. You should be able to find nginx.conf in your server’s /etc/nginx directory. First, we’ll discuss some global settings, then go module by module through the file, talking about which settings let you achieve good performance under heavy client loads and why they improve performance. A complete configuration file is at the end of this article.
Top-Level Configuration
In the nginx.conf file, Nginx has a few high-level configuration directives above the module sections.
- user www-data;
- pid /var/run/nginx.pid;
- worker_processes auto;
- worker_rlimit_nofile 100000;
user and pid should stay at their default settings – we won’t change these, as doing so makes no difference.
worker_processes defines the number of worker processes Nginx uses to serve web requests. The optimal value depends on many factors, including (but not limited to) the number of CPU cores, the number of hard drives storing data, and the load pattern. When unsure, setting it to the number of available CPU cores is a good starting point (setting it to “auto” will try to detect this automatically).
worker_rlimit_nofile changes the maximum number of open file descriptors limit for worker processes. If unset, this value is the operating system’s limit. Setting it allows your OS and Nginx to handle more files than “ulimit -a” reports, so set this value high so nginx doesn’t run into “too many open files” issues.
Events Module
The events module contains all the settings in Nginx that handle connections.
- events {
- worker_connections 2048;
- multi_accept on;
- use epoll;
- }
worker_connections sets the maximum number of simultaneous connections that can be opened by one worker process. If we set the aforementioned worker_rlimit_nofile, we can set this value very high.
Keep in mind that the maximum number of clients is also limited by the number of available socket connections on the system (~ 64K), so setting an unrealistically high value offers no benefit.
multi_accept tells nginx to accept as many connections as possible after receiving a new connection notification.
use sets the polling method used for multiplexing client threads. If you use Linux 2.6+, you should use epoll. If you use *BSD, you should use kqueue.
(It’s worth noting that if you don’t know which polling method Nginx should use, it will choose the one best suited for your operating system.)
HTTP Module
The HTTP module controls all the core features of Nginx HTTP processing. Because there are only a few configurations here, we’ll just excerpt a small portion of the configuration. All of these settings should be within the http module, and you might not even particularly notice this block of settings.
- http {
- server_tokens off;
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- …
- }
server_tokens does not make nginx execute any faster, but it can turn off the Nginx version number in error pages, which is good for security.
sendfile enables sendfile(). sendfile() can copy data between the disk and a TCP socket (or between any two file descriptors). Pre-sendfile involves allocating a data buffer in user space before transmitting data. Then read() copies data from the file into this buffer, and write() writes the buffer data to the network. sendfile() reads data immediately from disk into the OS cache. Because this copying is done within the kernel, sendfile() is more efficient than combining read() and write() and opening/closing/discarding buffers (more about sendfile).
tcp_nopush tells nginx to send all header files in one data packet, rather than sending them one by one.
tcp_nodelay tells nginx not to buffer data, but to send it in segments–when data needs to be sent promptly, this attribute should be set for the application, so that sending a small piece of data does not wait for a return value immediately.
- access_log off;
- error_log /var/log/nginx/error.log crit;
access_log sets whether nginx will store access logs. Turning this option off makes disk I/O read operations faster (aka, YOLO).
error_log tells nginx to only log critical errors:
- keepalive_timeout 10;
- client_header_timeout 10;
- client_body_timeout 10;
- reset_timedout_connection on;
- send_timeout 10;
keepalive_timeout assigns a keep-alive link timeout to the client. The server will close the connection after this timeout expires. We set it lower so nginx can keep working longer.
client_header_timeout and client_body_timeout set the timeout for the request header and request body (respectively). We can also set these lower.
reset_timedout_connection tells nginx to close connections from unresponsive clients. This will free up the memory space occupied by that client.
send_timeout specifies the response timeout to the client. This setting is not used for the entire forwarder, but only between two client read operations. If the client does not read any data within this period, nginx closes the connection.
- limit_conn_zone $binary_remote_addr zone=addr:5m;
- limit_conn addr 100;
limit_conn_zone sets the parameters for shared memory used to hold various keys (like the current number of connections). 5m is 5 megabytes, and this value should be set large enough to store (32K*5) 32-byte states or (16K*5) 64-byte states.
limit_conn sets the maximum number of connections for a given key. Here the key is addr, and the value we set is 100, meaning we allow each IP address to have up to 100 simultaneous open connections.
- include /etc/nginx/mime.types;
- default_type text/html;
- charset UTF-8;
include is simply an instruction to include the contents of another file within the current file. Here we use it to load a list of MIME types that will be used later.
default_type sets the default MIME-type for files.
charset sets the default character set in our headers
- gzip on;
- gzip_disable "msie6";
- # gzip_static on;
- gzip_proxied any;
- gzip_min_length 1000;
- gzip_comp_level 4;
- gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip tells Nginx to send data in compressed gzip format, which reduces the amount of data we send out.
gzip_disable disables gzip compression for specified clients. We set it to IE6 or lower to ensure broad compatibility with our setup.
gzip_static tells Nginx to look for pre-gzipped resources before compressing them on the fly. This requires you to pre-compress your files (it’s commented out in this example), allowing you to use the highest compression ratio without having Nginx compress them on the fly (for more detailed information on gzip_static, click here).
gzip_proxied allows or disables compression of the response stream based on the request and response. We set it to “any,” meaning all requests will be compressed.
gzip_min_length sets the minimum number of bytes for which compression is enabled. If a request is smaller than 1000 bytes, it’s better not to compress it, as compressing such small data can slow down the processes handling these requests.
gzip_comp_level sets the data compression level. This level can be any value from 1 to 9, with 9 being the slowest but offering the highest compression ratio. We set it to 4, which is a good compromise setting.
gzip_type sets the data formats to be compressed. The example above includes some common ones, but you can add more formats as needed.
- # cache informations about file descriptors, frequently accessed files
- # can boost performance, but you need to test those values
- open_file_cache max=100000 inactive=20s;
- open_file_cache_valid 30s;
- open_file_cache_min_uses 2;
- open_file_cache_errors on;
- ##
- # Virtual Host Configs
- # aka our settings for specific servers
- ##
- include /etc/nginx/conf.d/*.conf;
- include /etc/nginx/sites-enabled/*;
open_file_cache enables caching and specifies the maximum number of files to cache, as well as the caching time. We can set a relatively high maximum time so cached items are purged after being inactive for more than 20 seconds.
open_file_cache_valid specifies the interval for checking the validity of information within open_file_cache.
open_file_cache_min_uses defines the minimum number of file accesses within the inactive period specified in open_file_cache for a file to remain cached.
open_file_cache_errors specifies whether to cache error information when searching for a file, and also allows adding files to the configuration again. We also include server modules, which are defined in separate files. If your server modules are located elsewhere, you’ll need to modify this line to point to the correct location.
A Complete Configuration
- user www-data;
- pid /var/run/nginx.pid;
- worker_processes auto;
- worker_rlimit_nofile 100000;
- events {
- worker_connections 2048;
- multi_accept on;
- use epoll;
- }
- http {
- server_tokens off;
- sendfile on;
- tcp_nopush on;
- tcp_nodelay on;
- access_log off;
- error_log /var/log/nginx/error.log crit;
- keepalive_timeout 10;
- client_header_timeout 10;
- client_body_timeout 10;
- reset_timedout_connection on;
- send_timeout 10;
- limit_conn_zone $binary_remote_addr zone=addr:5m;
- limit_conn addr 100;
- include /etc/nginx/mime.types;
- default_type text/html;
- charset UTF-8;
- gzip on;
- gzip_disable "msie6";
- gzip_proxied any;
- gzip_min_length 1000;
- gzip_comp_level 6;
- gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
- open_file_cache max=100000 inactive=20s;
- open_file_cache_valid 30s;
- open_file_cache_min_uses 2;
- open_file_cache_errors on;
- include /etc/nginx/conf.d/*.conf;
- include /etc/nginx/sites-enabled/*;
- }
After editing the configuration, confirm and restart nginx to apply the changes.
- sudo service nginx restart