We hope you find this tutorial helpful. In addition to guides like this one, we provide simple cloud infrastructure for developers. Learn more →

How To Optimize Nginx Configuration

PostedMarch 17, 2014 441.4k views Server Optimization Nginx



Nginx is a fast and lightweight alternative to the sometimes overbearing Apache 2. However, Nginx just like any kind of server or software must be tuned to help attain optimal performance.


Worker Processes and Worker Connections

The first two variables we need to tune are the worker processes and worker connections. Before we jump into each setting, we need to understand what each of these directives control. The worker_processes directive is the sturdy spine of life for Nginx. This directive is responsible for letting our virtual server know many workers to spawn once it has become bound to the proper IP and port(s). It is common practice to run 1 worker process per core. Anything above this won't hurt your system, but it will leave idle processes usually just lying about.

To figure out what number you'll need to set worker_processes to, simply take a look at the amount of cores you have on your setup. If you're using the DigitalOcean 512MB setup, then it'll probably be one core. If you end up fast resizing to a larger setup, then you'll need to check your cores again and adjust this number accordingly. We can accomplish this by greping out the cpuinfo:

grep processor /proc/cpuinfo | wc -l

Let's say this returns a value of 1. Then that is the amount of cores on our machine!

The worker_connections command tells our worker processes how many people can simultaneously be served by Nginx. The default value is 768; however, considering that every browser usually opens up at least 2 connections/server, this number can half. This is why we need to adjust our worker connections to its full potential. We can check our core's limitations by issuing a ulimit command:

ulimit -n

On a smaller machine (512MB droplet) this number will probably read 1024, which is a good starting number.

Let's update our config:

sudo nano /etc/nginx/nginx.conf

worker_processes 1;
worker_connections 1024;

Remember, the amount of clients that can be served can be multiplied by the amount of cores. In this case, we can server 1024 clients/second. This is, however, even further mitigated by the keepalive_timeout directive.


Another incredibly important tweak we can make is to the buffer size. If the buffer sizes are too low, then Nginx will have to write to a temporary file causing the disk to read and write constantly. There are a few directives we'll need to understand before making any decisions.

client_body_buffer_size: This handles the client buffer size, meaning any POST actions sent to Nginx. POST actions are typically form submissions.

client_header_buffer_size: Similar to the previous directive, only instead it handles the client header size. For all intents and purposes, 1K is usually a decent size for this directive.

client_max_body_size: The maximum allowed size for a client request. If the maximum size is exceeded, then Nginx will spit out a 413 error or Request Entity Too Large.

large_client_header_buffers: The maximum number and size of buffers for large client headers.

client_body_buffer_size 10K;
client_header_buffer_size 1k;
client_max_body_size 8m;
large_client_header_buffers 2 1k;


Timeouts can also drastically improve performance.

The client_body_timeout and client_header_timeout directives are responsible for the time a server will wait for a client body or client header to be sent after request. If neither a body or header is sent, the server will issue a 408 error or Request time out.

The keepalive_timeout assigns the timeout for keep-alive connections with the client. Simply put, Nginx will close connections with the client after this period of time.

Finally, the send_timeout is established not on the entire transfer of answer, but only between two operations of reading; if after this time client will take nothing, then Nginx is shutting down the connection.

client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

Gzip Compression

Gzip can help reduce the amount of network transfer Nginx deals with. However, be careful increasing the gzip_comp_level too high as the server will begin wasting cpu cycles.

gzip             on;
gzip_comp_level  2;
gzip_min_length  1000;
gzip_proxied     expired no-cache no-store private auth;
gzip_types       text/plain application/x-javascript text/xml text/css application/xml;

Static File Caching

It's possible to set expire headers for files that don't change and are served regularly. This directive can be added to the actual Nginx server block.

location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
expires 365d;

Add and remove any of the file types in the array above to match the types of files your Nginx servers.


Nginx logs every request that hits the VPS to a log file. If you use analytics to monitor this, you may want to turn this functionality off. Simply edit the access_log directive:

access_log off;

Save and close the file, then run:

sudo service nginx restart


At the end of the day a properly configured server is one that is monitored and tweaked accordingly. None of the variables above are set in stone and will need to be adjusted to each unique case. Even further down the road, you may be looking to further your machine performance with research in load balancing and horizontal scaling. These are just a few of the many enhancements a good sysadmin can make to a server.

Submitted by: Alex Kavon


  • Great tutorial! Useful and well-written. One thing: It's good practice to test your configuration changes after making them, before restarting nginx so perhaps add one final step before "service nginx restart" to recommend the user enter "nginx -t" to make sure there are no typos etc in your configuration changes.
  • Also need to know which version you use. Because all your setting have directive error. nginx 1.1.19
  • @vartanjean7 The stable version of nginx is now 1.6, and the mainline version is at 1.7. If you're using 1.1.x in mid-2014, you should upgrade your package. (Those directive errors are because you are using very outdated software.)
  • Why is Debian listed as a requirement? Wouldn't these configurations be applicable to an Ubuntu installation?

  • @gustavojimenez.folta: The paths to some configuration files might differ from Ubuntu to Debian but since Ubuntu is based on Debian you should be fine following this tutorial on an Ubuntu system.

  • Thank you. I wondered because a lot of the configurations aren't present in my nginx.conf and I wasn't sure where to place things like client_body_buffer_size, etc.

    Having a look here gave me a better understanding in case anyone else is wondering the same. <a target="_blank" href="http://nginx.org/en/docs/http/ngx_http_core_module.html">http://nginx.org/en/docs/http/ngx_http_core_module.html</a>

  • Adding the following

    location ~* .(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 365d;

    gives me the following error "location" directive is not allowed here in /etc/nginx/nginx.conf:60.

    Am I missing something?


    • I'm just getting to making these edits myself, but it's my understanding that those lines don't go n your nginx.conf file, they go in your server block file (/etc/nginx/sites-available/your-site

      I also read, but am still unsure if this detail (so ignore it unless it doesn't seem to work), that you need to unlink your site (remove it from sites-enabled), and re-link it to the sites-enabled directory. Again, I read this on one site earlier, so take it with a grain of salt, and only try this if you're having issues.

  • I couldn't find these lines anywhere in nginx.conf ( I use Ubuntu 14.04):

    client_body_timeout 12;
    client_header_timeout 12;
    keepalive_timeout 15;
    send_timeout 10;


    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;

    Are those supposed to be in nginx.conf or somewhere else? If so, where do I need to put it exactly within the command lines? Just gotta be sure I'm doing it right. Thanks in advance!

  • Here is a common.conf I have that you can include in your server blocks to make adding servers easier.

    listen 80;
    index index.php index.html;
    # protect dotfiles
    location ~ /\. { deny all; error_log off; log_not_found off; }
    # ignore common 404s
    location = /robots.txt  { access_log off; log_not_found off; }
    location = /favicon.ico { access_log off; log_not_found off; }
    # case insensitive browser cache for static files
    # this is the same list as cloudflare plus extras
    location ~* \.(7z|ai|bmp|bz2|class|css|csv|docx?|ejs|eot|eps|flv|gif|gz|html?|ico|jar|jpe?g|js|json|lzh|m4a|m4v|midi?|mov|mp3|mp4|pdf|pict|pls|png|pptx?|ps|psd|rar|rss|rtf|svgz?|swf|tar|tiff?|ttf|txt|wav|webp|woff|xlsx?|zip)$ {
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    # static folders cache
    location ~ /(static|files|wp-content|images)/ {
        expires max;
        add_header Pragma public;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";

    Also make sure that if you're using regular expressions in the server_name that you give the original host name to PHP, otherwise $_SERVER['SERVER_NAME'] will be the regular expression!

    In the fastcgi_params file:

    fastcgi_param   SERVER_NAME     $host;
    • Also recommend throttling PHP requests to 1 per second per IP, there are many bots out there that like to brute force, my logs were filling up with 404's and failed login attempts, sometimes 10 per second.

      In nginx.conf:

      http {
          limit_req_zone  $binary_remote_addr  zone=php:10m  rate=1r/s;
          limit_req_log_level error;
          # return 429 (too many requests) instead of 503 (unavailable)
          limit_req_status 429;
          limit_conn_status 429;

      PHP location block in server would look something like this:

      location ~ \.php$ {
          limit_req zone=php burst=1 nodelay;
  • [Tutorial correction]To avoid error in nginx.conf:

    I think access_log off
    Must be access_log off; (add semicolon)

  • I'm curious, the ulimit command gives me a very different number when checking as SUDO vs. standard user. Anyone know why this is or which I should take as the truth?

    • I always log into "real root", i.e: sudo su and believe that when it comes to query system resources as root is a lower, accessible user that has almost unlimited access to things in the system. Sudo in my jurisdiction is an "almost root", but not a complete one.
      Conclusion, only believe what root says.

  • Is there any reason application/javascript was not included in gzip_types in the Gzip Compression section?

    • application/x-javascript covers Javascript files, but you can add application/javascript if you like.

    • It seems you can't reply to a reply on here :/ This is a reply to @kamaln7:

      Apparently application/x-javascript is deprecated and has since been fixed. Also some people seem to be having issues with it.

      So I don't think it might be the best advice to have just application/x-javascript in this otherwise great tutorial!

  • Hi. I use nginx 1.6 and ab to benchmark my wordpress site(simple installation, just for tests). According to this tutorial my nginx now is more slow then before. Without these changes i can make more request per second than now. Can someone explain me why this is happening.

  • Great tutorial :) Thanks.

    I added an event block and defined worker_connections to 12288 (for 12 cores VPS).
    My nginx.conf block looks like that:

    events {
            worker_connections 12288;
            multi_accept on;

    After saving the file and restart nginx service Im still getting 1024 when running 'ulinit -n' command.
    What should be the issue?


  • Suddenly my droplet is using 100% CPU usage.There are multiple php5-fpm processes which are eating up all the CPU when I enable port 80. Any help please...

  • HI

    large_client_header_buffers 2 1k;

    this should be in http block on i should create a server block for this?

    when i trying to enter my wordpress admin panel im always getting

    400 Bad Request Request Header Or Cookie Too Large nginx

    i searched in web and i found i should make largeclientheader_buffers 4 32k;
    is that ok?

  • Hi @huynhnangit

    thanks for your reply. i didnt understand what u mean by default. could you plz tell me in a but details plz.

    thanks in advance

  • Hi there,

    Thanks for the tutorial. I have a quick question though. I have previously followed this process for a 2GB server and when running ulimit -n I get 1024. I am now following the same process on an 8GB server and the number is the same.

    The article suggests that this is actually a low number (for a 512MB server) I would have expected it to be higher on a server that is $75 more expensive if that is the case.

    Could you just confirm whether I need to tweak anything on the server to increase this number or is this just a standard number?

    When running ulimit with -S or -H the returned value is unlimited

  • How to adjust correctly maximum opened files by system? because its related with worker_connections

  • If I set in php.ini:

    upload_max_filesize = 2M
    max_file_uploads = 20

    Then to what size do I set the client_body_buffer_size and client_max_body_size ?
    Can the buffer/body size be 2M or must it be 20x2=40M or more?
    And will timeouts also be affected by this?

  • Why don't you use nproc instead of grep processor /proc/cpuinfo | wc -l?

  • Do you make all these changes in the nginx.conf file, because I can't follow.

Creative Commons License