Rails 3 shows 404 error instead of index.html (nginx + unicorn)

Miko asked:

I have an index.html in public/ that should be loading by default but instead I get a 404 error when I try to access http://example.com/

The page you were looking for doesn’t exist.

You may have mistyped the address or the page may have moved.

This has something to do with nginx and unicorn which I am using to power Rails 3

When take unicorn out of the nginx configuration file, the problem goes away and index.html loads just fine.

Here is my nginx configuration file:

upstream unicorn {
    server unix:/tmp/.sock fail_timeout=0;
}

server {
    server_name example.com;
    root /www/example.com/current/public;
    index index.html;

    keepalive_timeout 5;

    location / {
        try_files $uri @unicorn;
    }

    location @unicorn {
        proxy_pass http://unicorn;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
}

My config/routes.rb is pretty much empty:

Advertise::Application.routes.draw do |map|
  resources :users
end

The index.html file is located in public/index.html and it loads fine if I request it directly: http://example.com/index.html

To reiterate, when I remove all references to unicorn from the nginx conf, index.html loads without any problems, I have a hard time understanding why this occurs because nginx should be trying to load that file on its own by default.

Here is the error stack from production.log:

Started GET "/" for 68.107.80.21 at 2010-08-08 12:06:29 -0700
  Processing by HomeController#index as HTML
Completed   in 1ms

ActionView::MissingTemplate (Missing template home/index with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml, :haml], :formats=>[:html], :locale=>[:en, :en]} in view paths
"/www/example.com/releases/20100808170224/app/views", 
"/www/example.com/releases/20100808170224/vendor/plugins/paperclip/app/views", 
"/www/example.com/releases/20100808170224/vendor/plugins/haml/app/views"):
/usr/local/rvm/gems/ruby-1.9.2-rc2/gems/actionpack-3.0.0.beta4/lib/action_view/paths.rb:14:in `find'
  /usr/local/rvm/gems/ruby-1.9.2-rc2/gems/actionpack-3.0.0.beta4/lib/action_view/lookup_context.rb:79:in `find'
  /usr/local/rvm/gems/ruby-1.9.2-rc2/gems/actionpack-3.0.0.beta4/lib/action_view/base.rb:186:in `find_template'
  /usr/local/rvm/gems/ruby-1.9.2-rc2/gems/actionpack-3.0.0.beta4/lib/action_view/render/rendering.rb:45:in `_determine_template'
  /usr/local/rvm/gems/ruby-1.9.2-rc2/gems/actionpack-3.0.0.beta4/lib/action_view/render/rendering.rb:23:in `render'
  /usr/local/rvm/gems/ruby-1.9.2-rc2/gems/haml-3.0.15/lib/haml/helpers/action_view_mods.rb:13:in `render_with_haml'
  etc...

nginx error log for this virtualhost comes up empty:

2010/08/08 12:40:22 [info] 3118#0: *1 client 68.107.80.21 closed keepalive connection

My guess is unicorn is intercepting the request to index.html before nginx gets to process it.

My answer:


The problem is here:

    try_files $uri @unicorn;

This should read:

    try_files $uri $uri/ @unicorn;

Which also eliminates the need to use an evil if, and doesn’t require you to have Rails serve static files (which is slow).


View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.