Ubuntu Gutsy - Nginx vhosts, rails and mongrels

There are several ways of serving a Ruby on Rails application, one of which is to use Nginx to proxy requests to mongrels.

There are a few ways of completing this and we're going to look at one solution. Other methods, such as using a mongrel cluster will be looked at in future articles.


Setup

Just a quick note on where we are in the setup. I installed MySQL and Ruby on Rails as per this article.

Once the basics were done I then proceed to install Nginx.

I then created a public_html folder in my home partition and created the correct permissions as shown here. The article is for Apache but the principles still apply.

Rails Application

You can use a pre-existing Rails application or, like me, create a new one from scratch. To create a new one, move into your public_html folder:

cd /home/demo/public_html

and create a new Ruby on Rails application:

rails railsapp

move into the directory:

cd railsapp

You will notice that the created folders are very similar to the default vhosts layout I describe here

As such, we don't need to create any extra folders as the Nginx logs can go into /log and so on.

Mongrels

Let's install the mongrels via ruby gems:

sudo gem install mongrel

As I am using rubygems 1.0.1 it installed the dependencies automatically and, on my setup, installed the following:

gem_plugin-0.2.3
daemons-1.0.9
fastthread-1.0.1
cgi_multipart_eof_fix-2.5.0
mongrel-1.1.3

Once done we can move onto the Nginx configuration.

Virtual host

Now we need to create a new virtual host for the 'railsapp' we created earlier.

Remember that we are using the sites-available and sites-enabled folders for your vhosts as it is incredibly easy to administer this way: Each domain has it's own configuration file and turning domains on and off is as simple as creating and deleting a symlink:

sudo nano /etc/nginx/sites-available/domain.com

Obviously use your domain name instead of my example of domain.com

At this stage we are only doing a basic configuration so you can enter the following in the vhosts file:

upstream domain1 {
        server 127.0.0.1:8000;
        server 127.0.0.1:8001;
    }

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


server {
            listen   80;
            server_name domain.com;

            access_log /home/demo/public_html/railsapp/log/access.log;
            error_log /home/demo/public_html/railsapp/log/error.log;

            root   /home/demo/public_html/railsapp/public/;
            index  index.html;

            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 false;

                          if (-f $request_filename/index.html) {
                                           rewrite (.*) $1/index.html break;
                          }

                          if (-f $request_filename.html) {
                                           rewrite (.*) $1.html break;
                          }

                          if (!-f $request_filename) {
                                           proxy_pass http://domain1;
                                           break;
                          }
            }

}

Take each section at a time and you will see that the basics are the same as for a 'normal' Nginx vhost.

We have the server_name, listen, log and index variables.

Where it differs is the addition of the Rails proxy settings.

In this example, we will use 2 mongrels running on ports 8000 and 8001 which I have defined in the 'upstream' setting. I've called it domain1 for ease of use.

The location settings say that if the requested file exists to serve the static version straightaway.

If the requested file doesn't exist, pass the request on to the mongrels. In this case it would proxy to 127.0.0.1:8000 and 8001 as those are the ports we defined at the beginning of the file.

There are more settings you can use but we'll stick with the basics right now and look at some advanced settings in a later article.

Enable

Don't forget to enable the new vhost or you'll scratch your head wondering why the domain is not showing (I didn't forget that. No sir):

sudo ln -s /etc/nginx/sites-available/domain.com /etc/nginx/sites-enabled/domain.com

Stop and start Nginx (a restart does not seem to work - any ideas welcome):

sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start

Start your engines

All that's left is to start the two mongrel processes on the ports defined in the upstream setting in the vhost.

If you are not already in your railsapp directory, move there now:

cd /home/demo/public_html/railsapp

Start the two mongrel instances:

mongrel_rails start -d -e production -p 8000 -P log/mongrel8000.pid
mongrel_rails start -d -e production -p 8001 -P log/mongrel8001.pid

Navigate

Once done, navigate to your domain:

http://www.domain.com

And, if you created a new Ruby on Rails application, you will see this:

Ruby on Rails Welcome Page

Summary

Proxying to mongrels to serve your Ruby in Rails application is relatively easy with Nginx.

Don't forget to check out the mongrel clusters article which explains how to set up a mongrel cluster so you don't have to enter multiple commands to start and stop your mongrels.

PickledOnion.

Article Comments:

matthew Hooks commented Mon Jan 28 22:02:53 UTC 2008:

How do we test rails if we don't currently have a domain or are just trying to access the development server that comes with rails? I can't seem to access my server by going straight to http://ipaddress:port/.

Yaphi commented Tue Jan 29 23:33:03 UTC 2008:

@Matthew

You can access your local rails dev server (which is probably mongrel) by accessing http://localhost:3000

daniel commented Mon Feb 04 17:43:10 UTC 2008:

I've followed this tutorial however, when I type http://www.mydomain.com it always redirects me to http://mydomain.com. This is more of an annoyance than a problem. How do I force nginx to keep the www prepended to the url?

PickledOnion commented Mon Feb 04 17:50:43 UTC 2008:

Hi Daniel,

It's the first server section in the vhost shown above.

Simply delete it if you don't want that to happen.

PickledOnion

Justin Blake commented Wed Feb 06 20:44:05 UTC 2008:

Daniel, just an FYI, redirecting to a single domain (whether with or without www) is usually desirable for SEO reasons. It keeps your page rank from being split between two "sites" and avoids duplicate content issues.

Rodrigo commented Mon Feb 11 12:49:43 UTC 2008:

I have installed Nginx and set up as the article says. When I go to my domain I see the rails index page but when I click on About application's environment I get a "The page you were looking for doesn't exist." error, same when I try to navigate to other controllers, does anyone know what could possibly be wrong?

Thanks

Rodrigo

Tony commented Wed Feb 13 13:36:29 UTC 2008:

I have a similar problem to Rodrigo.

I navigate to my domain and see that rails index page, but clicking on 'About Application's Environment' brings up a box with '502 Bad Gateway'.

Any help appreciated.

Cam commented Thu Feb 21 10:54:32 UTC 2008:

Tony & Rodrigo, You can only see that information if you accessing it from a localhost, it's not public. And nor would you want it to be, it contains vital info about your setup, that you never want hacker to have even a possibility of finding.

seth commented Wed Feb 27 23:04:44 UTC 2008:

If I type in www.mydomain.com/resource it redirects to mydomain.com without the /resource is there a way to make it redirect to mydomain.com/resource instead?

Thank you

Gordon McCreight commented Tue Mar 04 21:08:39 UTC 2008:

@Matthew: Another trick for testing if you don't actually have the domain is to fake it on the machine you'll be testing from (not on the server you're running on slicehost).

All computers (including Windows computers) check the /etc/hosts file for domain name to IP address resolution prior to checking DNS servers, so you can easily (for only your machine) make any domain name point to any IP address.

Run the command:

sudo nano /etc/hosts

Then add a couple lines which have the IP address of the server on slicehost followed by the domain name, like so:

xx.xxx.xxx.x www.domain.com xx.xxx.xxx.x domain.com

You'll probably want to add both of those lines, not just the www.domain.com one, since the nginx server will redirect you from www.domain.com to domain.com, which doesn't exist either. (See the earlier comments about redirecting)

seth commented Fri Mar 07 16:39:26 UTC 2008:

Figured out how to do what I was trying to do with the redirect.

I wrote it like this:

rewrite ^(/.*) http://domain.com$1 permanent;

Jason commented Fri Mar 07 22:45:42 UTC 2008:

I am having the same problem as Daniel. I have removed the first server section entirely, but it still redirects from www.domain.com to domain.com. How can I fix this?

diz commented Mon Mar 10 03:45:39 UTC 2008:

I'm very frustrated. I've followed these instructions to the letter, and I still get 404 errors whether I use my custom rails app or a new rails app.

Nginx log file looks like it's still trying to find files here "/usr/local/nginx/html/index.html" no matter what I do.

I've even modified the default Nginx config file in sites-available to no avail. :(

diz commented Mon Mar 10 19:43:31 UTC 2008:

never mind me... three days... hardly any sleep...

but I got it working. :)

eighth time was the charm ;)

Brad commented Thu Mar 13 02:59:47 UTC 2008:

I get:

We're sorry, but something went wrong (500).

We've been notified about this issue and we'll take a look at it shortly.

After setting up per article with mongrel cluster. any ideas?

replicant commented Wed Mar 19 02:57:36 UTC 2008:

diz, why don't you tell us what you did to fix your issue, please sir? for the benefit of those folks that may run into the same issue, but are still not able to fix it.

Cathal commented Fri Apr 04 20:25:02 UTC 2008:

How would you go about configuring nginx to serve your rails app. from a path other than the root? All examples I've seen so far map 'location /' to the rails app. However, I'd like to use 'location /app1' to act as my rails app. root. Is this possible?

shoesandships commented Thu Apr 10 16:45:23 UTC 2008:

I was getting a 502 error until I changed root /home/demo/public_html/railsapp/public/; to root /home/demo/public_html/railsapp/; and deleted index index.html;

zach commented Fri Apr 25 20:02:01 UTC 2008:

Hi, I'd like to suggest that the line rewrite ^/(.*) http://domain.com permanent; above be changed to rewrite ^/(.*) http://domain.com/$1 permanent;

Otherwise requests like www.domain.com/path/to/something get redirected to plain ol' domain.com. Maybe there's something I missed, but I think most people would probably like to keep the full path as the default behavior.

And by the way, thanks for the great article!

ynw commented Wed Apr 30 00:50:00 UTC 2008:

It worked well with some minor changes

adam.setzler commented Wed Apr 30 06:59:22 UTC 2008:

@Tony and Rodrigo

You wanted to know how to redirect .domain.com to www.domain.com. Here's how:

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

server { listen 80; server_name www.domain.com; [/code]

"server_name domain.com" is looking for access to your domain without the "www" (.domain.com). It will then rewrite the request to "www.domain.com".

When the server sees a request to "www.domain.com" (from the rewrite rule), it will then carry out the directives for "server_name www.domain.com".

Hope this helps.

Russell commented Sun May 25 00:01:27 UTC 2008:

I got this error when installing mongrel :

sh: make: not found

fixed it by doing this : apt-get install make

iwan commented Sat Jun 28 14:15:13 UTC 2008:

"I got this error when installing mongrel : sh: make: not found fixed it by doing this : apt-get install make"

... but now i get: make: cc: Command not found make: * [fastthread.o] Error 127 (...)

After trying with "apt-get install gcc" get new errors: make cc -I. -I/usr/lib/ruby/1.8/x8664-linux -I/usr/lib/ruby/1.8/x8664-linux -I. -fPIC -fno-strict-aliasing -g -O2 -fPIC -c fastthread.c In file included from fastthread.c:12: /usr/lib/ruby/1.8/x86_64-linux/ruby.h:40:21: error: stdlib.h: No such file or directory (...)

All libraries are missing :-(

josh commented Tue Jul 08 06:11:29 UTC 2008:

@iwan and @Russell I had the same prob - you need to install the build essentials:

aptitude install build-essential -y

Daniel Waite commented Mon Aug 25 19:14:35 UTC 2008:

Is there a way to access the site via the Slice's IP address?

I've substituted domain1.com with the IP address of the Slice, and while Nginx and Mongrel start okay, I get an infinite redirect when hitting the IP address in the browser.

JLF commented Wed Aug 27 05:30:54 UTC 2008:

I followed josh advice to install mongrel, but I still get errors.

Building native extensions. This could take a while... ERROR: Error installing mongrel: ERROR: Failed to build gem native extension.

/usr/bin/ruby1.8 extconf.rb install mongrel creating Makefile

make cc -I. -I/usr/lib/ruby/1.8/x8664-linux -I/usr/lib/ruby/1.8/x8664-linux -I. -fPIC -fno-strict-aliasing -g -g -O2 -fPIC -c fastthread.c In file included from fastthread.c:12: /usr/lib/ruby/1.8/x86_64-linux/ruby.h:40:21: error: stdlib.h: No such file or directory /usr/lib/ruby/1.8/x86_64-linux/ruby.h:44:21: error: string.h: No such file or directory /usr/lib/ruby/1.8/x86_64-linux/ruby.h:54:19: error: stdio.h: No such file or directory /usr/lib/ruby/1.8/x86_64-linux/ruby.h:71:20: error: alloca.h: No such file or directory In file included from /usr/lib/gcc/x86_64-linux-gnu/4.2.3/include/syslimits.h:7, from /usr/lib/gcc/x86_64-linux-gnu/4.2.3/include/limits.h:11, from /usr/lib/ruby/1.8/x86_64-linux/ruby.h:91, from fastthread.c:12: /usr/lib/gcc/x86_64-linux-gnu/4.2.3/include/limits.h:122:61: error: limits.h: No such file or directory In file included from /usr/lib/ruby/1.8/x86_64-linux/ruby.h:718, from fastthread.c:12: /usr/lib/ruby/1.8/x86_64-linux/missing.h:16:24: error: sys/time.h: No such file or directory /usr/lib/ruby/1.8/x86_64-linux/missing.h:25:25: error: sys/types.h: No such file or directory In file included from /usr/lib/ruby/1.8/x86_64-linux/ruby.h:719, from fastthread.c:12: /usr/lib/ruby/1.8/x8664-linux/intern.h:219: error: expected declaration specifiers or '...' before 'fdset' /usr/lib/ruby/1.8/x8664-linux/intern.h:219: error: expected declaration specifiers or '...' before 'fdset' /usr/lib/ruby/1.8/x8664-linux/intern.h:219: error: expected declaration specifiers or '...' before 'fdset' /usr/lib/ruby/1.8/x86_64-linux/intern.h:219: warning: 'struct timeval' declared inside parameter list /usr/lib/ruby/1.8/x86_64-linux/intern.h:219: warning: its scope is only this definition or declaration, which is probably not what you want ....

ChrisC commented Mon Sep 08 21:53:16 UTC 2008:

aptitude install build-essential -y

Thanks Josh, I had the same prob and that fixed it.

gladwright commented Thu Sep 25 04:04:05 UTC 2008:

Thanks for the great tutorials! Suggest clarifying "and, on my setup, installed the following" in the mongrel install section. I'm a newbie and I'm not sure what "on my setup" means. The gem list command allowed me to verify the presence of the items you listed. Perhaps that's what you were referring to. Thanks again for the great tutorials! They are helping me so much!

Frank commented Thu Oct 09 22:09:34 UTC 2008:

I think that instead of starting and stopping Nginx, you can just type: kill -HUP NGINXPIDNUMBER_HERE. Especially in production. To find out the PID number type: ps aux | egrep '(PID|nginx)'

jack commented Thu Feb 26 13:11:03 UTC 2009:

You might get the message:

"We're sorry, but something went wrong (500).

We've been notified about this issue and we'll take a look at it shortly."

I think this because there's an error (whether it be a syntax error or database connection etc), and in production mode the normal stack trace is not shown. That is normal I reckon.

StoreCrowd commented Wed Jun 03 04:29:48 UTC 2009:

One thing to note about Nginx is that rewrite rules are different. Especially if you're hosting a Wordpress blog.

There is a discussion on the forum if anyone needs help:

http://forum.slicehost.com/comments.php?DiscussionID=2087

bg commented Wed Jun 10 06:23:20 UTC 2009:

Very appreciative of the great tutorials on slicehost. Currently installing Nginx on my local dev box from source in preparation for installing on my slicehost account. All is good except I am unable to get nginx use the vhost I set up. I went through the installation and config tutorials, but it only seems to serve up the default host and content. Any thoughts would be very much appreciated.

Kathleen Yowler commented Tue Aug 18 18:29:10 UTC 2009:

@Brad I had the same issue. I just ran rails railsapp again and it started working.

Yousuf commented Wed Jan 20 16:04:16 UTC 2010:

I followed exactly this tutorial but still receive "Server not found" problem when trying to access the virtual host. Any help? Thanks in advance!

Want to comment?


(not made public)

(optional)

(use plain text or Markdown syntax)