Ubuntu Hardy - Nginx, rails and thin

Having installed the thin web server for Ruby, we can now look at configuring a Nginx vhost to proxy to thin so we can serve our Ruby on Rails application.

The process is easy to follow and easy to repeat for hosting multiple domains.


Setup

Firstly you will have needed to follow the previous Nginx articles and installed via aptitude or via source.

You will also need to have installed the thin web server as per the article linked to above.

Plan

The plan is very simple:

We'll create a basic rails application and use 3 thin instances running from port 3000 to 3002.

I won't go into detail as the thin web server for Ruby article shows how to install and configure thin.

Once that is done, we'll create a simple vhost to proxy requests to the thin instances.

You may also notice this article is very similar to the Nginx and mongrels article. There is a very good reason for that - they use exactly the same methods in creating the virtual host.

All the virtual host has to do is proxy requests to the 3rd party web server - in this case thin, in the sister article, mongrels.

Rails Application

To create a rail application, move into your public_html folder:

cd /home/demo/public_html

and create a new Ruby on Rails application:

rails railsapp

Done.

Thin

Ensure you are in the rails folder:

cd ~/public_html/railsapp

Then create a thin configuration file:

sudo thin config -C /etc/thin/railsapp.yml -c /home/demo/public_html/railsapp/  --servers 3 -e production

It's always a good idea to check the created file:

cat /etc/thin/railsapp.yml

The contents are as such:

pid: tmp/pids/thin.pid
log: log/thin.log
timeout: 30
max_conns: 1024
port: 3000
max_persistent_conns: 512
chdir: /home/demo/public_html/testapp
environment: production
servers: 3
address: 0.0.0.0
daemonize: true

Unlike with mongrels, we don't need to manually create symlinks, etc to make sure thin is started on a reboot.

Now all we need to do is start thin:

sudo /etc/init.d/thin start

Done.

Nginx Virtual Host

Let's create the Nginx vhost:

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

Note: If you installed Nginx from source, the path may vary to something like:

sudo nano /usr/local/nginx/sites-available/domain.com

The contents of the file are as such:

upstream domain1 {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        server 127.0.0.1:3002;
    }

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 3 thin instances running on ports 3000, 3001 and 3002 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 straight away.

And if the requested file doesn't exist, pass the request to the thin server.

Enable

Remember that we need to 'enable' any available vhosts or it won't be served (an easy thing to leave out).

Referring to the Nginx articles, all we need to do is create a simple symlink:

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

Or, if you installed from source:

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

Done.

Restart

Final step is to restart Nginx:

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

Use the 'stop' and 'start' method as issuing a restart command does not always work with Nginx.

Navigate

All that's left is to navigate to your domain:

http://www.domain.com

Where you will be greeted with the rails welcome page.

Summary

Setting up Nginx virtual hosts to proxy to the thin server easily completed.

To serve multiple domains, simply repeat the process with the new domain details.

PickledOnion.

Article Comments:

jjburka commented Tue Jun 03 02:14:33 UTC 2008:

thanks for the tutorial, I think you have a typo in the ngnix file the upstream addresses should be 127.0.0.1:port

PickledOnion commented Tue Jun 03 08:51:59 UTC 2008:

Hi jjburka,

I don't understand your comment.

The upstream addresses are 127.0.0.1:port

'upstream domain1 { server 127.0.0.1:3000; server 127.0.0.1:3001; server 127.0.0.1:3002; } '

Could you expand on what you mean?

PickledOnion

Todd Dewell commented Tue Jun 03 18:08:15 UTC 2008:

Is there any way for these commands to only start and stop the thin servers associated with a specific Rails app?

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

For instance if you configure them like this: testapp thin ports 4000, 4001, 4002 baseapp thin ports 3000, 3001, 3002

When you run /etc/init.d/thin stop it will stop the thin servers on both applications.

jjburka commented Fri Jun 06 13:16:11 UTC 2008:

sorry , I meant to write: I think you need to write the config file for the thin processes to use the address 127.0.0.1 via "-a 127.0.0.1" or in the nginx config file have the address set to 0.0.0.0 since thin defaults to that.

Julian Burgess commented Sun Jun 22 11:48:55 UTC 2008:

How can I set up Nginx to pass errors 404 and 500 to the pages I've setup in rails /public? Thanks

Ed Ruder commented Mon Jun 23 02:41:43 UTC 2008:

A note that might save others from wasting the time I just did--if you click the "About your application’s environment" link on your vanilla Rails app's "Welcome Aboard" page that's running in production mode, the link won't work. And that's the correct behavior.

daeltar commented Wed Jul 02 08:07:33 UTC 2008:

Recomend using socket instead of TCP/IP ports in nginx+thin combo.

csbartus commented Mon Nov 17 18:31:35 UTC 2008:

a quick how-to using sockets instead TCP/IP ports on nginx+thin:

http://rubypond.com/articles/2008/02/06/improving-rails-app-and-mongrel-performance-with-thin/

gsaravia commented Tue Jan 27 20:40:43 UTC 2009:

I am getting: $ sudo /etc/init.d/thin start sudo: /etc/init.d/thin: command not found

i followed the previous instructions on installing thin - any reason this would be happening?

Also, i am not sure if this is related, but on the thin config line i had to manually create the /etc/thin directory.

Luke commented Fri Apr 24 20:01:00 UTC 2009:

I have exactly the same problem that gsaravia describes above.

Luke commented Fri Apr 24 20:04:44 UTC 2009:

solved: the command "sudo thin install" had been forgotten.

franee commented Thu Jan 07 16:32:07 UTC 2010:

new nginx versions now use off instead of false for parameters.

instead of:

proxy_redirect false;

should be:

proxy_redirect off;

laura reid commented Tue Apr 24 22:07:11 UTC 2012:

Is this article still relevant?

John commented Wed Jul 17 09:35:06 UTC 2013:

Could it be that I should use another port, as port 80?

John commented Wed Jul 17 09:35:09 UTC 2013:

Could it be that I should use another port, as port 80?

Want to comment?


(not made public)

(optional)

(use plain text or Markdown syntax)