46

What best practices do you use while using NGinx?

The Pixel Developer
  • 847
  • 3
  • 9
  • 20
  • Just a note that this does not work for a Magento setup. Still investigating the reasons but I think it has something to do with the query string. – Jauder Ho Jun 04 '09 at 08:26
  • location /wordpress must be useful when you have wordpress in subdirectory named "wordpress". What about when we have wordpress in web root "/"? – rahul286 Dec 10 '09 at 12:24

15 Answers15

21

How to combine HTTP and HTTPS blocks.

server {
    listen 80;
    listen 443 default ssl;

    # other directives
}

This was posted as an answer to a different question. See here.

Jauder Ho
  • 5,337
  • 2
  • 18
  • 17
21

By far, the best tips I have ever seen are from the author on it's pitfall page: https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/

Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
Roger
  • 473
  • 11
  • 22
15

Generally, using "if" is a bad practice (according to author of nginx). if possible, better to use try_file of error_page directives instead "if (-f ...)"

Combining tip with maintenence.html file and tip with try_files we get:

location / {
    try_files /maintenance.html $uri $uri/ @wordpress;
}

When maintenance ends, just mv maintenance.html from $root.

Slava K
  • 66
  • 1
  • 4
  • 16
    This is not ideal as /maintenance.html will be served as a 200 response. You probably want search engines to recognize that the maintenance page is not your actual website. You would probably want to return a 503 (Service Temporarily Unavailable). The only way I can figure out how to do this is with an `if (-f ...) { return 503; }` and `error_page 503 /maintenance.html`. What do you think? – Aaron Gibralter Jun 02 '11 at 14:08
11

Configure nginx to use stronger SSL ciphers. By default, SSLv2 is enabled (which you should disable if possible).

ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;

http://tumblelog.jauderho.com/post/121851623/nginx-and-stronger-ssl

Jauder Ho
  • 5,337
  • 2
  • 18
  • 17
8

Its often more efficient to use the map directive in place of regular expressions when switching the root for matching subdomains:

server {

    server_name mysite.tld ~^.+\.mysite\.tld$;

    map $host $files {
        default            common;
        mysite.tld         common;
        www.mysite.tld     common;
        admin.mysite.tld   admin;
        system.mysite.tld  system;
        *.mysite.tld       users;
    }

    root /var/www/mysite/$files;

}
Phillip B Oldham
  • 1,016
  • 5
  • 15
  • 24
8

The empty_gif module is also very useful, especially if you need monitor responses from the webserver (using nagios/monit/etc):

location /token {
    empty_gif;
}

location /favicon.ico {
    empty_gif;
}

location /img/1px.gif {
    empty_gif;
} 
Phillip B Oldham
  • 1,016
  • 5
  • 15
  • 24
6

We set up Nginx with Chef, using this cookbook which contains scripts for handling nginx configuration similar to how Debian does Apache2, and also some sample templates with sane defaults.

jtimberman
  • 7,511
  • 2
  • 33
  • 42
5

Here's a good method for returning a maintenance page. All requests are rewritten and the correct http code is returned. (503 - Service unavailable)

error_page 503 /maintenance.html;

location /
{
    if (-f $document_root/maintenance.html)
    {
        return 503;
    }

    try_files $uri /index.php?$args;
}

location = /maintenance.html
{
    rewrite ^ /maintenance.html break;
}
The Pixel Developer
  • 847
  • 3
  • 9
  • 20
  • 1
    Actually, I disagree -- I added a comment to http://serverfault.com/questions/18994/nginx-best-practices/124755#124755. Basically, you want to return a 503 error or else bots and indexers will think your maintenance page is part of your actual site... There's nothing wrong with an `if` statement if you use it correctly -- the docs say that `if`s are safe if you're just doing `return xxx;`. – Aaron Gibralter Jun 02 '11 at 14:10
  • Also, is `location = /maintenance.html { break; }` necessary? – Aaron Gibralter Jun 02 '11 at 14:12
4

From nginx 0.7.12 and later, a "" is usable in server_name to catch requests without a "Host" header.

You can use the following as a catchall for undefined virtual hosts.

server {
  server_name _ "";
}
Unknown
  • 1,675
  • 6
  • 20
  • 27
  • Does your exemple work only for requests with an undefined vhost or will it also work with requests with an unknown (wrong) vhost? – Benoit Jun 04 '09 at 08:26
  • @Benoit it works for anything that is not defined. – Unknown Jun 08 '09 at 00:49
  • Is " server_name _ * " is not supported nginx 0.7 onwards? – rahul286 Dec 10 '09 at 12:19
  • 1
    Please note this is only partially true. "" will catch a MISSING Host header, but it will not be catch a request with a Host header that doesn't match anything. If you want a catch-all server block then see the default_server flag under the listen directive. – Martin Fjordvald Apr 09 '11 at 23:48
3

I also posted a while ago about how to properly handle gzip compression with nginx as older browsers may have issues with just a blanket gzip statement. HTH.

http://tumblelog.jauderho.com/post/27655495/gzip-compression-with-nginx

Jauder Ho
  • 5,337
  • 2
  • 18
  • 17
3

I don't know if it is a best practice, but definitely a neat hack to get nested conditions in nginx. Here's a sample from the nginx wiki.

location /xxxx/ {
  set $test "";

  if ($request_method = POST) {
    set $test  P;
  }

  if ($http_cookie ~* "CCCC=.+(?:;|$)" ) {
    set $test  "${test}C";
  }

  if ($test = PC) {
    #rewrite rule goes here.
  } 
}
p.campbell
  • 4,397
  • 6
  • 40
  • 51
sajal
  • 582
  • 6
  • 12
  • 3
    I'd put that in the category of "ugly but occasionally necessary practice" -- certainly not something to be encouraged. – womble Jul 30 '11 at 02:56
2

If you need to flip contextually between http and https for subdomains handled by the same server block, you can use variables to do so. Might not be the most efficient way to do things, but it works:

server {
  server mysite.tld ~^.+\.mysite\.tld$;

  set $req_ssl = 0;

  map $host $files {
      default            common;
      mysite.tld         common;
      www.mysite.tld     common;
      admin.mysite.tld   admin;
      system.mysite.tld  system;
      *.mysite.tld       users;
  }

  root /var/www/mysite/$files;

  if ( $files = "admin" ){
    set $req_ssl 1;
  }

  if ( $files = "common" ){
    set $req_ssl 2;
  }

  if ( $scheme = http )
  {
    set $req_ssl $req_ssl.1;
  }

  if ( $scheme = https )
  {
    set $req_ssl $req_ssl.2;
  }

  if ($req_ssl = 1.1){
    rewrite ^ https://$host$uri;
  }

  if ($req_ssl = 2.2){
    rewrite ^ http://$host$uri;
  }

}
Phillip B Oldham
  • 1,016
  • 5
  • 15
  • 24
2

I always try to use the root directive in the top of the server block so I can take advantage of the $document_root variable and never, but never, include the root directive inside a location block.

The Pitfalls Page from the Nginx wiki has some great tips about best practices.

Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
1

If you are using nginx as a proxy, having the timeout settings adjusted can be important to ensure you are not having nginx drop connections before your application is done with them, especially if you are dealing with a high traffic application:

proxy_connect_timeout
proxy_send_timeout
wjimenez5271
  • 709
  • 2
  • 6
  • 16
0

Did you take a look over here?

http://www.directadmin.com/forum/showthread.php?p=137288

KPWINC
  • 11,274
  • 3
  • 36
  • 44