Running Ruby applications with Mongrel and Apache2

Posted by Steve on Thu 1 Feb 2007 at 15:35

When you start working with Ruby on Rails applications you're probably content with using the integrated HTTP server, webbrick, for development. Once you're using them in production though you'll want something more capable. This is where mongrel comes in.

There are several options for integrating Ruby on Rails applications within an Apache2 server, the most common are:

  • Running them as CGI processes using mod_fastcgi
  • Running them under mongrel and using Apache's proxy support to forward requests.
    • This is the setup we'll be examining here.

By default when you've created a new Ruby on Rails application several files with have been generated for you, notably:

  • script/server - This is a small webserver which can be used for testing work.
  • public/dispatch.cgi - This is a CGI interface for your application

Using the server is very simple, but it doesn't scale well. To start it just run script/server:

steve@steve:~/Rails/Books$ ./script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2007-02-01 15:11:41] INFO  WEBrick 1.3.1
[2007-02-01 15:11:41] INFO  ruby 1.8.5 (2006-08-25) [i486-linux]
[2007-02-01 15:11:41] INFO  WEBrick::HTTPServer#start: pid=9558 port=3000

Here you can see that we've started a server listening upon port 3000, with the WEBrick HTTP server. This allows you to test your application.

When it comes to deployment the simplest solution is to install the mongrel HTTP server - this is a small server which can be used to start your application, and is powerful enough to be used in production.

(Mongrel also supports clustered operation, which we'll not discuss here.)

To install Mongrel you'll use the gem command, which allows you to add or remove ruby-specific extensions upon your Debian machine. If you've installed the rubygems package from the source distribution you may execute:

root@host:~# gem install mongrel

The Debian rubygems package places the gem command in a location which is probably not upon your PATH, so you will need to fully qualify the location of the command:

root@host:~# /var/lib/gems/1.8/bin/gem install mongrel

Either way you should see something like the following:

Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i486-linux)
 1. mongrel 1.0.1 (ruby)
 2. mongrel 1.0.1 (mswin32)
 3. mongrel 1.0 (mswin32)
...

Enter "1" to choose the most recent version of the server, which is not compiled for Microsoft Windows.

Note: You must have a compiler and development environment setup, as well as the appropriate ruby-dev package in order to build the shared-library mongrel uses.

If you're missing these you can install them by running:

root@host:~# apt-get install ruby1.8-dev build-essential 

Once Mongrel has been installed you can start it up to host your project by executing the following, from the root of your application:

skx@host:~/Rails/Books$ mongrel_rails start -d -e production -a 127.0.0.1 -p 3000

Here we've used several arguments (for an overview of more options run "mogrel_rails start -t") here is a quick explanation of what they mean:

  • -d
    • To detach and run in the background
  • -e production
    • To run the application in "production" mode.
  • -a 127.0.0.1
    • To bind to the localhost only.
  • -p 3000
    • To listen upon port 3000.

Note: you don't need to start the server as root, since you're binding to a "non privileged" port.

All being well you should receive no errors and browsing at http://localhost:3000 should show you your applications front page.

To stop the server you may run:

skx@host:~/Rails/Books$ mongrel_rails stop
Sending TERM to Mongrel at PID 9698...Done.

If this works we can look at adding a handler for Apache2 to make it externally visible.

The first thing to do is to make sure that you have the mod_proxy module enabled for Apache. To do this run:

root@host:~# a2enmod  proxy
Module proxy installed; run /etc/init.d/apache2 force-reload to enable.

Now create a configuration file for your host within the directory /etc/apache2/sites-available/ - here we'll be using the hostname test.example.com, so we'll create the file with the same name.

The contents of the file would look like this:

<VirtualHost *>
    # Server name
    ServerName test.example.com

    # Proxy ACL
    <Proxy *>
        Order allow,deny
        Allow from all
    </Proxy>

    # Proxy directives   
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/
    ProxyPreserveHost on

    # Logfiles
    ErrorLog  /var/log/apache2/test.example.com.error.log
    CustomLog /var/log/apache2/test.example.com.access.log combined

</VirtualHost>

Once you've created the configuration file you should enable the site and finally restart the Apache server:

root@host:~# a2ensite test.example.com
Site test.example.com installed; run /etc/init.d/apache2 reload to enable.
root@host:~# /etc/init.d/apache2 restart

If you've done this correctly you should now be able to visit http://test.example.com/ which will cause Apache2 to forward your request, or proxy, to the local mongrel server running upon localhost on port 3000.

In addition to the logfiles from Apache you'll also see ruby-specific logging in the log/ subdirectory of your application.

 

 


Posted by ptecza (193.0.xx.xx) on Fri 2 Feb 2007 at 14:34
It's not a joke or start of flame war. It's a serious question for such Perl lover as Steve ;)

Do you code Ruby apps, because you want to do it or because you need it? I'm asking you, because I'm very curious.

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Fri 2 Feb 2007 at 15:00
[ View Steve's Scratchpad | View Weblogs ]

The thing which inspired this particular article was the migration of a PHP-based blog over to a Ruby-based one.

Ruby the language I like, because it is small, uniform, and reasonably well designed.

I'm getting a little experience with Ruby on Rails and find that a pleasant and fun way to develop simple applications with - but there is so much "magic" in the framework that I'm not sure I'd feel the same way about larger projects. (I've not used it enough to know yet.)

I don't have much patience for language wars, although at the same time I do have a strong Perl-preference. Mostly I believe learning new languages, toolkits, and environments is almost always a useful thing to do - even if you don't use them again.

I'm not sure I really answered that terribly well, but I hope it gave you something to work with!

Steve

[ Parent | Reply to this comment ]

Posted by ptecza (83.16.xx.xx) on Sat 3 Feb 2007 at 20:41
Thanks a lot for your answer, Steve! I'm satisfied fully ;)

So, I have no exit plan and I have to try Ruby ;)

[ Parent | Reply to this comment ]

Posted by shoof (70.90.xx.xx) on Fri 2 Feb 2007 at 15:02
[ View Weblogs ]
It is better for performance to let Apache handle the static requests (images, stylesheets etc..)

This can be done easily with mod_rewrite.

RewriteEngine On

RewriteRule ^/$ /index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule .* http://localhost:3000%{REQUEST_URI} [P,QSA]


This checks if the file is static and lets apache handle it, everything else goes to mongrel.

[ Parent | Reply to this comment ]

Posted by sfrank (82.141.xx.xx) on Fri 2 Feb 2007 at 15:31
Here is a good article on how to get multiple mongrel processes and Apache's mod_proxy_balancer serve requests thru those multiple pre-started mongrel instances. If your Rails app receives a lot of visitor, this might help on getting them served without too much of delay.

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Fri 2 Feb 2007 at 15:43
[ View Steve's Scratchpad | View Weblogs ]

Thanks for sharing, the tip about a file for maintenance is neat, as is letting Apache serve some of the files directly.

Steve

[ Parent | Reply to this comment ]

Posted by mcphail (62.56.xx.xx) on Fri 2 Feb 2007 at 21:42
I'm a little wary of mixing gems with apt. Has anyone had any problems with this?

[ Parent | Reply to this comment ]

Posted by Steve (62.30.xx.xx) on Sat 3 Feb 2007 at 17:39
[ View Steve's Scratchpad | View Weblogs ]

Seems to work well if you install the rubygems package, but I've not used source installs to know how that works out.

Steve

[ Parent | Reply to this comment ]

Posted by Anonymous (87.247.xx.xx) on Wed 7 Feb 2007 at 15:34
We have our website on ryby+rails on debian etch.
Some my experience:
without fcgi (fastcgi) - very slow.
With fcgi - much better speed, but sadly not stable, when load increased from just developers to some more people.
(working load for website with ruby: ~5000 visitors/day, ~30000 pages/day)

Now it works for about half year with such config:
apache2 - main server (static content, some php, some perl, dynamic compression)
pen - load balancer among mongrel processes
8 mongrel processes - it may seem pradoxal with 1 CPU, but with complex page with many flash.swf etc. 8 mongrel processes working in parralel gives out page much quicker, than with only one process.

Sig.

[ Parent | Reply to this comment ]

Posted by Anonymous (70.19.xx.xx) on Thu 15 Feb 2007 at 00:41
Why would I want to use mongrel when mod-fcgid scales better?

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Thu 15 Feb 2007 at 10:02
[ View Steve's Scratchpad | View Weblogs ]

Mongrel scales impressively well with its own clustering support.

mod-fcgid appears to no longer be recommended for running rails applications - I know that I had significant load problems with it in production.

Still use whichever you prefer .. you have the freedom to choose.

Steve

[ Parent | Reply to this comment ]

Posted by Anonymous (62.159.xx.xx) on Thu 8 Mar 2007 at 09:55
hi there,

I have another related question:

I have severall sites running on my server with ROR. I am still using fastcgi and have problems switching to fcgid... Have tried reading o nthe net for severall day, still no luck.

No I found your article and have been considering switching to mongrel for ROR content but still there is one problem I had:

say customer_x makes changes to his site, he requests me to do a killall dispatch.fcgi to reflect those changes to the production environment. I am just wondering how I could give him the possibility to kill his own process? The dispatch.fcgi processes are running as www-data (debian apache user).

any hints or links for me please?

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Thu 8 Mar 2007 at 10:39
[ View Steve's Scratchpad | View Weblogs ]

Give him sudo access to run "/etc/init.d/apache2 restart" or "apache2 reload".

Steve

[ Parent | Reply to this comment ]

Posted by Anonymous (62.159.xx.xx) on Thu 8 Mar 2007 at 10:50
sorry for not being very specific, my fault.

of course I could d othis, but I don't want every client restarting apache2 :-)

I heard rumours one could get fastcgi or fcgid running with suexec? suexec is already working for my server with cgi scripts but I couldn't get it running with fcgid... is there a possibility to have it running somehow with mongrel and suexec? so this one customer could restart his mongrel processes? And have his own processes (mongrel) run as his user/group?

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Thu 8 Mar 2007 at 10:58
[ View Steve's Scratchpad | View Weblogs ]

Mongrel can certainly run as its own user, so you could do it that way. But I'm unsure about fcgid - I stopped using it very quickly as it just wasn't stable enough.

Sudo seems like the right thing to do, if you can't/won't use mongrel - but be careful you don't give them the ability to kill all process! ;)

Steve

[ Parent | Reply to this comment ]

Posted by Anonymous (62.159.xx.xx) on Thu 8 Mar 2007 at 11:11
further above you state:

[quote]Once Mongrel has been installed you can start it up to host your project by executing the following, from the root of your application:

skx@host:~/Rails/Books$ mongrel_rails start -d -e production -a 127.0.0.1 -p 3000
[/quote]

does this mean that I could setup their vhost for proxying, having apache2 serve static content and proxy all other requests to mongrel? as these users have chrooted access, I could include mongrel into the chroot, and as they would start their own mongrel processes they could also kill them, but they could pass too many variables to mongrel, possibly this is giving them to many options and too much responsibility for the user...

I guess if I can't get fcgid running with suexec I will have to use the sudo solution.


thx for helping :-)

[ Parent | Reply to this comment ]

Posted by Steve (80.68.xx.xx) on Thu 8 Mar 2007 at 11:13
[ View Steve's Scratchpad | View Weblogs ]

Yes, if apache2 is doing the proxying then the mongrel's can be run as a regular user - either in a chroot or not.

They can then restart their own mongrel themselves.

Steve

[ Parent | Reply to this comment ]

Posted by kirstin (70.19.xx.xx) on Tue 20 Mar 2007 at 23:01
fcgid runs perfectly fine with suexec, eg.
You need libapache2-mod-fcgi & libfcgi-ruby, et. al.

blah blah blah

AddHandler fcgid-script .fcgi
SuExecUserGroup migrane migrane

DocumentRoot /var/www/migrane/public

<Directory /var/www/migrane/public/>
Options MultiViews ExecCGI
AllowOverride None
Order allow,deny
allow from all

RewriteEngine On
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
</Directory>

blah blah blah

But make sure that migrane *owns* public and public/dispatch.fcgi and that the latter is executable -- this is mostly likely the source of your frustration.

Note that setting RAILS_ENV is broken with sarge fcgid. As a work around, I set it in dispatch.fcgid based on the hostname and/or path. Also, the sarge libapache2-mod-fcgid has a bug preventing file uploads with ssl, but it's easy to backport the etch version.

[ Parent | Reply to this comment ]

Posted by kirstin (70.19.xx.xx) on Wed 21 Mar 2007 at 00:24
No longer recommended for rails? I don't think that's exactly a concensus.

I'm curious about your load issues, because there should be less overhead using fcgid than mongrel (fastcgi is a far less complex protocol than http), and because fcgid's behavior is much more flexible (e.g. it's able to add rails processes on demand, and can respawn old or unresponsive processes, etc.) It could, for instance, be configured to exactly mimic mongrel's load behavior by setting a fixed process count. What did you set your DefaultMaxClassProcessCount to?

In fact, it's mongrel's lack of support for periodically restarting processes that makes me most uncomfortable with it--ruby not being the most robust of languages, I really wouldn't want to run a rails process indefinitely. But I do appreciate mongrel's ability to run in a cluster without needing a web server on each node. On the other hand, I'm glad to run apache on each node if it gives me fcgid's advantages.

[ Parent | Reply to this comment ]

Posted by Anonymous (208.35.xx.xx) on Tue 3 Jun 2008 at 19:51
It also need enable proxy_http to make it work.

[ Parent | Reply to this comment ]

Sign In

Username:

Password:

[Register|Advanced]

 

Flattr

 

Current Poll

What do you use for configuration management?








( 453 votes ~ 5 comments )