"Curiosity is the very basis of education and if you tell me that curiosity killed the cat, I say only the cat died nobly." - Arnold Edinborough

Nginx is a constantly evolving web server rapidly growing in popularity. In July of 2013 nginx even managed to become the most used web server amongst the top 1000 sites ranked by traffic. It’s safe to say that these days you cannot afford to not know about nginx or how to use it. Unfortunately the nginx documentation is more of an API documentation than it’s an introduction to how nginx actually works. This post is aimed at correcting that by walking you through the most important parts of the nginx configuration file in a logical order.

The Basics of the Nginx Configuration

Nginx is in all fairness a fairly simple HTTP server, however, because most people come from Apache there are a few gotchas in the nginx configuration that people need to be aware of before they start using this web server. The most important is that nginx is a reverse proxy first and HTTP server second, its first concern is not files but rather URLs, this changes the way we have to configure nginx.

The first thing you need to know is that the nginx configuration file uses an inheriting hierarchy, directives specified in a higher block will filter down to lower blocks as a default value, from this follows that we want to specify things in the top most hierarchy whenever possible. Since directives in top blocks filter down as default values it is still possible to override them in most cases.

There are 3 hierarchies which are usually referred to as blocks. The HTTP-block, the server-block and the location block of which the hierarchy goes like this: http -> server -> location.

Furthermore there are two special locations, an event block and the root which the event block and the http block reside in. Both of these contain only a minor amount of directives. The majority of your time will be spent in the other three blocks.

The blocks have a semantic meaning of sorts. The server block is what in Apache would be considered a virtual host. The location block usually referrers to the URI.

When using the documentation the context keyword specifies in which block a directive may be used, as mentioned earlier it is usually recommended to specify the directive in the top most block.

Virtual Hosts

To begin with the most interesting directives are server_name and root. The former instruct nginx to use this server block when the HOST header matches the value and the latter defines what to use as root when looking for files.

This forms the basic of our virtual hosts, an example would be:

server {
    listen          80;
    server_name     domain.com *.domain.com;
    return          301 $scheme://www.domain.com$request_uri;
 }

server {
    listen          80;
    server_name     www.domain.com;

    index           index.html;
    root            /home/domain.com;
}

Here we have two virtual hosts. The first one is hit when domain.com or any subdomain of domain.com except for www is sent as the HOST header by the browser. The reason for this is that nginx will always choose the most specific match, and if visting www.domain.com then this will match the second block precisely.

This also means you can create a default virtual host to catch all domains without a proper match. Thankfully this is as simple as adding the default_server flag to the listen directive. This causes all request without a HOST header or without another vhost matching the HOST header to be sent to this vhost instead. Examples are requests accessing the IP directly or if someone points a random domain at your IP. The server_name _; which you will see mentioned in a lot of guides means nothing and does nothing. It’s just a bogus invalid HOST header that can be used to make sure nothing ever matches it. You should be able to simply not define a server_name.

server {
    listen          80 default_server;

    index           index.html;
    root            /var/www/default;
}

Locations

If you’re switching from Apache to nginx then this is where you want to pay attention. Nginx typically does not use complicated rewrites – usually we can accomplish the same using a location block.

The most important things to note are that locations, with the exception of named locations, works on the URI without any query parameters and only one location block will ever be run. This is also why I recommend putting directives in the top most block. A root directive defined in location / will not be available in location /images – unless defined in the server block. I trust you see how defining things in the upper most block will prevent code duplication and headaches.

Another important point about locations is that, as with server_name directive, nginx will use the most specific location block. There are a few rules for how specific various setups will be, the location directive documentation entry explains this very well, so you should read that first.

Let us look at a few examples of how to use a location block. In this example we’ve run a forum on URI /forum/ and have recently moved it to a subdomain. We now need to redirect the old URLs to the new URLs. To do this we use a regex location with a named variable and then issue our redirect.

server {
    listen          80 default;
    server_name     www.domain.com;

    root            /home/domain.com;

    # This will match any URI beginning with /forum
    location ~ ^/forum/(?P.*)$ {
        return 301 $scheme://forum.domain.com/$1;
    }
}

server {
    listen          80;
    server_name     forum.domain.com;

    index           index.php;
    root            /home/domain.com/forum;
}

The requests for /forum are now successfully transferred to our new subdomain while requests to files not in /forum will be served from our normal /home/domain.com root.

Handling PHP

PHP – or any backend really ties in well with locations, namely we can define a location block to catch all PHP files.

server {
    listen          80;
    server_name     forum.domain.com;

    index           index.php;
    root            /home/domain.com/forum;

    location ~* \.php$ {
        include fastcgi.conf # I include this in http context, it's just here to show it's required for fastcgi!
        try_files $uri =404; # This is not needed if you have cgi.fix_pathinfo = 0 in php.ini (you should!)
        fastcgi_pass 127.0.0.1:9000;
    }
}

As mentioned previously, nginx does not care about files but rather locations and this is why I have a try_files directive inside the php block. This location block matches a URI that ends in .php but it does not care if it’s a file or not. Therefore a request for /forum/avatars/user2.jpg/index.php will be matched and sent to PHP, and if PHP is not configured properly PHP will then execute /forum/avatars/user2.jpg when /forum/avatars/user2.jpg/index.php doesn’t exist. This provides a huge security risk. Do note that this is not a bug in nginx, it’s the intended behaviour and as such will not be “fixed”.

This can also be fixed on the PHP side by setting cgi.fix_pathinfo=0 in the php.ini file.

The end result, though, is that .php files which exist will be passed via fastcgi to our PHP processes running on port 9000.

The Finishing Touch – SEF URLs

This setup works, but all the craze these days is to have search engine friendly URLs for SEO reasons. Usually this involves quite a few rewrites, but with nginx we can do it with just one line, provided the backend script is written in a sane way.

server {
    listen          80;
    server_name     forum.domain.com;

    index           index.php;
    root            /home/domain.com/forum;

    location / {
        try_files   $uri $uri/ /index.php;
    }

    location ~* \.php$ {
        include fastcgi.conf; # I include this in http context, it's just here to show it's required for fastcgi!
        try_files $uri =404; # This is not needed if you have cgi.fix_pathinfo = 0 in php.ini (you should!)
        fastcgi_pass 127.0.0.1:9000;
    }
}

Did you notice the change? It’s minimal really. The one try files line means that it will first try accessing the full URI, which means that a static file request will end here. Secondly it will try the full URI plus a slash, thus looking for a directory. Finally, if none of these are found it will send the request to /index.php and perform a new location match, which will of course hit our PHP location and fastcgi_pass the request. PHP will then have the full URI in $_SERVER['PATH_INFO']. Simple, elegant and easy to understand.

Debugging Requests

Nginx is a complicated server at times, thankfully we have an excellent error log available to us to help figure out where things are going wrong. If you check the error log directive in the documentation you will notice that it takes a second argument. This will let you define how much information is output by nginx. A value of warn will give you sufficient info to debug most issues.

For more detailed reading on debugging please see my debugging nginx errors post.

My Book

If you liked the style of this blog post then check out my nginx book – Instant Nginx Starter. It introduces you to the syntax and flow of nginx and minimizes your time spent debugging errors.

  • MTecknology

    Posted: July 28, 2010


    Nice little jump start to understanding blocks and servers. Reply


  • Mitur Binesderti

    Posted: September 7, 2010


    It would be helpful to mention, at least once, where these configuration files go... Reply


  • MTecknology

    Posted: September 7, 2010


    The configs would go... where every other config goes... /etc/ unless you installed from source in which case that should be entirely obvious. Reply


    • Brent Gulanowski

      Posted: March 29, 2011


      One of the marks of good writing is not assuming that your audience knows what you think to be "obvious". If your starting assumption is that your audience should be smart enough to know X then you are already excluding people unnecessarily. The whole point of writing is to share knowledge. Might as well do a complete job. Doesn't hurt to be redundant. If you don't want to do that, provide pointers for prerequisite knowledge. It's the right thing to do. Reply


      • fjordvald

        Posted: March 30, 2011


        The problem is that configs doesn't actually "go" anywhere. The default location of configuration files is /usr/local/nginx/conf/nginx.conf. But this with a source compile, then you have compile flags which changes the location and you have init scripts which can use the -c flag to specify which config file to use. And it all differs depending on whether you compile from source or use a repository.

        And you really do have to stop at some point, you can't assume people doesn't know anything at all. Do we then also have to tell people how to use their mouse? Covering how their repository install thing isn't something I'm capable of nor interested in, and if people compile from source then they should be able to figure out where stuff installs. Reply


        • Warren Wilkinson

          Posted: February 11, 2013


          So why not mention the default? I'd bet a large portion of your users aren't compiling from source and are instead using whatever ubuntu or debian or redhat gives them. For 90% of people, that's /usr/local/nginx/conf/nginx.conf. So mention it. Reply


          • Martin Fjordvald

            Posted: February 11, 2013


            Because there are too many variations for me to give a default and the people SHOULD know the most standard ones. Where config files are placed is not at all about nginx, it's about their OS. This is a primer about nginx and I'm not going to pretend I know how every OS out there install it.

            If you use CentOS and you do yum install x then you should know it installs config into the /etc/ directory. If you don't then you need to go back to basics and learn about your OS first. I specifically avoid talking about it because I don't want to cover your OS unless it directly pertains to something nginx, which default location for config file doesn't.

            If you compile from source then you should be familiar with the compile flags that specifically states right there in --help where the config will be placed. If you aren't then you shouldn't be compiling from source.


        • Tobias

          Posted: April 28, 2014


          Thankfully at least the discussion pointed me to the right directory.
          Apart from that the article was really helpful. Reply


      • MOGH

        Posted: May 21, 2011


        Even in school someone has to make the effort to understand when learning something new to them. Sometimes that means *going through the motions* with trying, but accept the failures too. Then moving forward to ask questions based upon some effort already made.


        A good place to start an understanding is here:
        http://wiki.nginx.org/InstallOptions
        Nginx, it is a very complex web server and has many options. I believe it is fair to say, for someone to try to give a complete understanding to everyone is asking a bit much in my opinion. With the information here and other places with some effort, someone will start to gain an understanding by working through it.


        Hope this helps. Reply


      • Baylink

        Posted: November 15, 2011


        Nerdview can be troublesome, yes. But in the case of "Where do the config files live?", the true answer is "wherever the heck your distro's packager thought they ought to go": package authors are notoriously bad about that.

        In CentOS 5, frex, they go where I would expect to find then: /etc/nginx, which just means that the CentOS architects and I have similar reflexes.

        The *real* answer is "install whatever package on your distro supplies locate, and do # updatedb after you install the package". If you're going to teach people something, *that* is what it ought to be. Reply


      • Tyrone Williams

        Posted: December 11, 2011


        To Mr. Martin Fjordvald, the author - Thank you so much , I just wish you were #1 on google and I didn't waste time on other instructions which confused the shit out of me. Thank you. wordpress finally is working and urls look pretty. thanx!.

        Below I address the idiots who bad mouth this article as too complex.

        -------------------------------------------------

        @Brent Gulanowski - I spent over 2 days , 10 hours each trying different instructions to get this specific part of the installation working. I was about to give up and pay $15, until I found this page that's written in plain language, that explained the concept of those blocks and their arrangement which allowed me to adapt my config and get it to work(php-fpc/nginx/ubuntu/sql/apc/memcache plugin/wordpress) that 18 other sites did not do (or did but the explanation went over my head).

        I never seen a Linux until yesterday morning, and I figured out where the config file is by looking around and first getting familiar with sudo and nano and mv and command prompt.
        --------

        Thank you again Mr. Martin Fjordvald Reply


  • Ben

    Posted: September 8, 2010


    @ Mitur

    This is the equivalent of more less (web.config in the windows world)

    it goes under etc/nginx/sites-available/domain.com if you installed nginx from a repository Reply


  • incel

    Posted: September 22, 2010


    Following the excellent guide posted in cyberciti.biz (http://www.cyberciti.biz/faq/rhel-fedora-install-configure-nginx-php5/) I istalled nginx
    in centos 5.5 successfully, but I fail to configure VirtualHosts.

    I tried different combinations but it does not work.

    Could you please help me?

    I just need an example of a working configuration.

    I really appreciate it.

    thank you.- Reply


    • fjordvald

      Posted: September 27, 2010


      The Nginx wiki has loads of examples, if you need help you should join us in the #nginx IRC channel on irc.freenode.org Reply


    • Johnny Peck

      Posted: November 30, 2010


      Make sure you have set your host names in the hosts file (/etc/hosts). If your localhost, default configuration is working then this is the most likely reason you can't get to your virtual hosts. Hope that helps. Reply


  • Kevin McCaughey

    Posted: February 5, 2011


    Thanks for your Blog Martin, it has been of great use to me whilst setting up nginx etc on my Linode. One thing I would love to see you do is an article on how (as on overview) all this stuff works together and what does what. e.g. in a PHP/MYSQL/NGINX/fpm etc setup, what each of the modules do and how they work together. There are a lot of setup guides out there, but I have never really understood the "why" of what I am doing, apart from the Nginx configuration, which I now understand better thanks to your blog.

    I think you would be a good person to explain it! :)

    Thanks again for your blog and keep posting! Reply


    • fjordvald

      Posted: February 10, 2011


      Thanks for the kind words. I'm not really sure if a post on this subject would be very useful as I tend to have an unorthodox setup, I rarely use yum/apt-get to install things like MySQL, PHP etc. Reply


  • Johans

    Posted: February 27, 2011


    Thanks for a nice intro to Nginx. I'll read the Packt book you reviewed next.

    BTW - the link to your Nginx/Apache post is broken - path is 2011/01, it should be 2011/02:

    http://blog.martinfjordvald.com/2011/02/nginx-primer-2-from-apache-to-nginx/ Reply


    • fjordvald

      Posted: March 2, 2011


      Thanks, glad you liked it.
      And the link has now been updated, thanks for reporting it. Reply


  • Giuseppe Russo

    Posted: April 16, 2011


    Hi,

    I read a couple of months ago in a hosting forum that its better to have a forum, a blog or other scripts in the root like www.mywebsite.com and not www.mywebsite.com/forum or www.mywebsite.com/blog because there will be problems with NginX.

    Sorry but don't remember that forum were hosting support wrote about that NginX problem.

    Is that correct?
    Does NginX require to install a blog in a subdomain like http://blog.mywebsite.com?

    I have websites with the blog in a folder and would like to know before installing NginX.
    Maybe your article explains this but I don't understand well, English isn't my first language.

    Giuseppe Reply


    • fjordvald

      Posted: April 17, 2011


      Hi,
      There's nothing to this rumour. Nginx will work no matter where you place your code so long as your configuration reflects this properly. The only problematic case is if you have PHP code in different roots, say some code in /home/user/public_html and some code in /var/www. It's still perfectly do-able but you then have to use multiple location blocks to capture PHP requests and make sure that PHP is sent the proper path.

      The reason I have the blog part as a subdomain is just that I prefer it and find it more organized than having it all as part of my domain root. Reply


  • Michiel Roos

    Posted: May 19, 2011


    For the PHP block use:
    try_files $uri =404
    instead of the if statement. Reply


    • fjordvald

      Posted: May 20, 2011


      I understand where you're coming from with if being evil and all that. However, the wiki is a bit "dramatic" for lack of a better word. If is quirky and unpredictable, however, it's consistent. So in this case there's nothing wrong with using an if to check for file existence.

      Whether you use if or try_files you'll still have a stat() call to check for existence. You'll functionally have the same outcome as well, in fact the only difference is that try_files will re-evaluate the location matching while if won't. So there's actually a tiny itsy bitsy advantage to using if over try_files. Reply


  • Danilo

    Posted: May 24, 2011


    Thank you a lot, happily flattr'd :) Reply


  • why

    Posted: June 7, 2011


    I don't get it. In Nginx's very own official pitfalls section, it states very clearly that "listen 80;" is a bad thing to do. Yet, it's added in almost every config I can find on the internet. Did I miss something? Reply


    • fjordvald

      Posted: June 7, 2011


      The pitfalls page is over-zealous in my opinion. It's not trying to say that it's "bad" but rather that it's "unnecessary". The meaning of the two things are completely different but the wiki doesn't really care. I'll talk with the other prominent wiki people and see if we can have it changed. Reply


  • Dan Dascalescu

    Posted: June 28, 2011


    Thanks for the intro!

    It would help to mention how to properly restart nginx for the config changes to take effect. I've seen sudo kill -HUP `cat /usr/local/nginx/logs/nginx.pid` recommended, but sometimes (I'm not sure why), that didn't exactly work, and I had to sudo service nginx stop, then kill the nginx pid, then sudo service nginx start. Reply


    • fjordvald

      Posted: June 30, 2011


      That's an OS issue, not a Nginx one. I really do not want to open up that can of worms. Sending HUP to Nginx will always make the workers reload the configuration. The only cases where you need to restart if you need the master process to do something such as bind to port 80. Reply


  • Glenn

    Posted: August 26, 2011


    Brilliant, thanks Martin, very helpful. Reply


  • nikita

    Posted: January 20, 2012


    what is the meaning of '^' in the line below?

    rewrite ^ http://www.domain.com$request_uri? permanent;

    thanks! Reply


    • fjordvald

      Posted: January 21, 2012


      Rewrite takes a regex to match against the URI, but since I don't care about what the URI is I just use a ^ which means "start of string" and thus matches everything. Reply


  • scott

    Posted: May 6, 2012


    this is an old post but this works for me on Centos 6

    # Generated by iptables-save v1.4.7 on Mon Feb 6 17:29:54 2012
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [4:496]
    -A INPUT -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 443 -j ACCEPT
    -A INPUT -p tcp -m state --state NEW,ESTABLISHED -m tcp --dport 80 -j ACCEPT
    -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -p icmp -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
    -A INPUT -j REJECT --reject-with icmp-host-prohibited
    -A FORWARD -j REJECT --reject-with icmp-host-prohibited
    COMMIT
    # Completed on Mon Feb 6 17:29:54 2012 Reply


  • lulalala

    Posted: July 6, 2012


    I am a bit lost in the paragraph where "This location block matches a URI that ends in .php but it does not care if it’s a file or not." Since you used try_files, nginx would actually care about existence of file. But that paragraph sounds as if it doesn't. Reply


    • mfjordvald

      Posted: July 6, 2012


      The location doesn't, which is why you need to make sure it is an actual file via try_files or to configure your PHP installation properly. Reply


  • daan

    Posted: August 15, 2012


    Nice one dude. GOing to try this tonight, Using perl dancer as my app and Starman as the back end server... hope it goes well Reply


  • zuzmoo

    Posted: August 21, 2012


    Hy!

    I tried to configure nginx with php5. I used this config: http://www.howtoforge.com/installing-php-5.3-nginx-and-php-fpm-on-ubuntu-debian
    but i get an error message if I try to load my info.php: file not found. There is a .html file in the same directory and it works fine. My php settings are wrong somewhere. In the nginx error log: "Primary script unknown" while reading response header from upstream.. Reply


    • mfjordvald

      Posted: August 21, 2012


      I cover that error here: http://blog.martinfjordvald.com/2011/01/no-input-file-specified-with-php-and-nginx/ Reply


  • kevin

    Posted: August 29, 2012


    I have a ruby install on media temple (dv) 4, plesk 11; If i add the correct locations block to one of the plesk generated files, the site works fine. The problem is if someone reconfigures plesk, plesk will auto-generate the files it needs and overwrite. I included nginx.conf in /var/www/vhosts/domain/conf, but it's not being picked up?

    Any ideas? Reply


    • mfjordvald

      Posted: August 31, 2012


      Plesk is a control panel that takes over administration of your server. That means stuff has to be done The Plesk Way. Therefore, ask Plesk for support as they're the ones who know best. Reply


  • prathima

    Posted: November 5, 2012


    Hi,

    Can you please tell me how to configure nginx as http1.1 server.
    what changes should i make it to use http1.1 version in my configuration file.

    your help is really appreciated.

    thanks Reply


    • mfjordvald

      Posted: November 5, 2012


      First of all you need to ensure you have a new enough version. Then you need to enable it with http://www.nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version
      I'd also recommend experimenting with http://www.nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive after that. Reply


  • Carsten

    Posted: November 18, 2012


    Thanks for the nice starter here.

    Would be nice to cover 404 redirects as well. Might interest some people.

    thanks from germany Reply


  • Mohsen

    Posted: January 7, 2013


    Very good!

    You just saved with "SEF URLs" section.

    Thanks from Iran. Reply


  • David

    Posted: February 25, 2013


    I popped over here from the Nginx wiki -- thanks for taking the time to explain things. I switched from Apache to Nginx about a year ago and I'm still finding things I can do to increase performance, there's just so much to know. I was admiring how this theme displays code, so I peaked under your hood (excuse the invasion), looked up your theme -- a typography theme, no wonder. Looks great! Reply


  • name

    Posted: July 10, 2013


    Elementary!

    "The configs would go... where every other config goes... /etc/"

    Wait... except for the ones in /opt ... well, /etc or /opt or actually pretty much any directory a developer chooses since there's nothing aside from convention to stop him.

    Anyways, one doesn't dive straight into this tutorial. One must first take the tutorial for the tutorial :) The it's all clear. Reply


  • Joe

    Posted: November 6, 2013


    This is a nice primer, except (considering it's a primer) you haven't mentioned where to actually *put* the configuration files. That would be very convenient to know. Reply


    • Martin Fjordvald

      Posted: November 6, 2013


      Please see this comment which deals exactly with that and why I don't cover configuration file location: http://blog.martinfjordvald.com/2010/07/nginx-primer/#comment-15680 Reply


  • John Evans

    Posted: April 27, 2014


    I read this post as I'm looking at trying Nginx out and switching from Apache. I thought the article was well laid out and explained a lot. I then got on to reading some of the comments and was instantly reminded of a post I wrote about the commenting habits of some people and it was a general rant people that only offer negative criticism.

    It was the part of the comments section dealing with the location of the config file that I was looking at. The author (Martin Fjordvald) has taken the time to write this post for the benefit of Nginx newbies like me and it is valued enough to be included on the Nginx wiki. I find it shocking that people can only see the negative aspects and cannot be bothered to get off of their arse and find out where the config file lives by themselves.

    Brent Gulanowski commented on what makes a good writer. Well Mr. Gaulanowski, I was a military instructor in the British Army for 10 years in subjects ranging from practical to theory and I can tell you that the mark of a good commenter is giving constructive feedback without discouraging the subject from giving his full effort on his next attempt.

    Rant over,
    :-) Reply


  • Woody

    Posted: May 5, 2014


    If this is a primer, can you explain everything when you use it. You spring "try_files" on me. What's that? You didn't define what that does. I might as well just go read the documentation first. Sorry for being annoyed sounding. Just trying to help you be a better primer writer. Reply


    • Martin Fjordvald

      Posted: May 6, 2014


      Hi Woody, you are right, my primer does assume a minimum reader engagement. I'm trying to enhance the documentation where I find it lacking - I'm not trying to replace it. You are expected to go read the documentation for more details on some of these directives. Reply



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>