1

I have a nginx + thin + Rails 3.2 setup. Currently I am trying to setup nginx so it can serve cached pages directly.

However nginx still pass *.html request to Rails in the following nginx configuration files. The html files exists in public folder, and nginx does find them, just that they are still passed to Rails.

upstream site {
  server unix:/home/site/deploy/site/shared/pids/thin.0.sock;
}

server {
  listen 80;
  server_name www.example.com;
  rewrite ^(/.*) http://example.com$1 permanent;
}

# asset server
server {
  listen 80;
  server_name assets.example.com;
  expires max;
  add_header Cache-Control public;
  charset utf-8;
  root   /home/site/deploy/site/current/public/;
}

# frontend
server {
  listen 80;
  server_name .example.com;
  charset utf-8;

  root   /home/site/deploy/site/current/public/;
  index  index.html;

  location ~* ^.+.(jpg|jpeg|gif|png|swf|zip|rar|doc|xls|exe|pdf|ppt|txt|tar)$ {
    root /home/site/deploy/site/current/public/;
    expires max;
    break;
  }

  # serve static files
  if (-f $request_filename) {
    break;
  }

  gzip on;

  location / {
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    if (-f $request_filename) {
      break;
    }

    if (-f $document_root/cache/$host/$uri/index.html) {
      rewrite (.*) /cache/$host/$1/index.html break;
    }

    if (-f $document_root/cache/$host/$uri.html) {
      rewrite (.*) /cache/$host/$1.html break;
    }

    if (-f $document_root/cache/$host/$uri) {
      rewrite (.*) /cache/$host/$1 break;
    }

    proxy_pass http://site;
    break;
  }
}

I am new to nginx, and this configuration file is copied from previous projects I have not worked on, so this is probably a very newbie question.

lulalala
  • 17,572
  • 15
  • 110
  • 169

2 Answers2

1

To allow nginx to serve static cached pages you need to use try_files, let me share the config:

upstream site {
  server          unix:/home/site/deploy/site/shared/pids/thin.0.sock fail_timeout=0;
}

server {
  listen          80;
  server_name     www.example.com;
  rewrite ^(/.*)  http://example.com$1 permanent;
}

server {
  listen          80;
  server_name     example.com;
  charset         utf-8;

  root            /home/site/deploy/site/current;
  try_files       $uri/index.html $uri @thin;

  gzip on;

  location @thin {
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  Host $http_host;
    proxy_redirect    off;
    proxy_pass        http://site;
  }

  location ~* ^.+.(jpg|jpeg|gif|png|swf|zip|rar|doc|xls|exe|pdf|ppt|txt|tar)$ {
    root             /home/site/deploy/site/current/public/;
    expires          max;
    break;
  }
}
Anatoly
  • 15,298
  • 5
  • 53
  • 77
  • thanks, but I think somewhere in my code prevent this to work. The access log says: `xxx.xx.xxx.xx - - [04/Jul/2012:12:28:03 +0000] "GET / HTTP/1.1" 200 4541 "-"`. Is it possible to see what went wrong in the logs? – lulalala Jul 04 '12 at 04:32
  • @lulalala try more detailed logs *error_log logs/nginx.error.log info; access_log logs/nginx.access.log info;* – Anatoly Jul 04 '12 at 04:40
  • no error occurs, and access.log seems to not have functionality to report other stuffs. Currently things still gets directed to Rails, I'll try to see if the path is wrong. – lulalala Jul 04 '12 at 05:04
  • @lulalala I forget to say, **root** should point to the application directory, not public dir inside (this is a difference between passenger module and upstream - mongrel,thin,unicorn,rainbows). I've updated answer, see above. – Anatoly Jul 04 '12 at 05:21
  • thanks, it does not work. But I just realized error log does not show any `trying to use file`, try_files probably didn't get called at all. – lulalala Jul 04 '12 at 07:51
  • @lulalala please put the logs here, what exactly does not work? what is your nginx version: run **nginx -V** – Anatoly Jul 04 '12 at 08:02
  • thanks, I have somehow fixed it and am faced with another problem. I'll edit your answer and once you agree I'll accept it? – lulalala Jul 05 '12 at 10:14
  • thanks, and if you don't mind would take look at my other question? http://serverfault.com/questions/405264/static-file-serving-only-works-if-root-is-a-subfolder-under-public – lulalala Jul 06 '12 at 04:11
  • @lulalala, author of nginx tells about **try_files** as better alternative to conditional expressions. – Anatoly Jul 17 '12 at 10:16
0

Here is a more general theoretical answer (SO editors rejected my edit to explain in the answer above.):

Nginx has a ngx_static module which is on by default. This module runs at end of the content phase. It will serve static files if no other content command in that location block can work in the request. It will also only work if the uri does not end with slash.

So to serve static files, one need to make sure the uri is a valid path name by the end of content phase, and there is no other content phase command that can serve stuff in the same location block.

In my case, I want to access cached page, I can use try_files to rewrite the uri. try_files works in a phase just before the content phase, which will check for existence of files. If one of them exist, then the uri is changed to that file. Then in the content phase it will be served.

What if I want to serve static file if it exists, or serve dynamic content if it does not? Usually serving dynamic content will prevent static file to be served. In this case a different location block can be used. If no static file is found during try_files, we jump to another location block (in the example @thin, where all dynamic contents are served. But if static file exists, we stay in the original location block, and as we enter the content phase, since there is no other content serving command, the static file is served.

lulalala
  • 17,572
  • 15
  • 110
  • 169