Open Source Institute | CyberArmy Intelligence & Security | CyberArmy Services & Projects

RE: [Ruby] Publishing Rails Applications


[Replies] [Reply] [View by Thread] [Help]
[Back To Article Discussion Forum]

Posted by Delta LtKer int16h On 2007-11-02 16:30:29
In Reply to [Ruby] Publishing Rails Applications Posted by Author nikkitracks On 2007-10-29 18:28:36

Delta LtKerDelta LtKer
Delta LtKer int16h



Great article, thanks! It's about time we had some decent non-PHP web development content! :)

I too thought it was slightly peculiar to use "publishing", but sticking to the norm and common is boring anyway! :]

(p.s. Rails ftw! ;)

On 2007-10-29 18:28:36, nikkitracks wrote
>View and vote on the article here: Publishing Rails Applications<br/><br/><hr width="90%"/><center><h3>Publishing Rails Applications</h3></center><table width="100%"><tr><td valign="top">Category</td><td width="100%"><center><table border="1" cellpadding="3" cellspacing="0" style="border-collapse: collapse" bordercolor="#000000" width="95%" bgcolor="#364C7D"><tr><td width="100%">Ruby</td></tr></table></center></td></tr><tr><td valign="top">Summary</td><td width="100%"><center><table border="1" cellpadding="3" cellspacing="0" style="border-collapse: collapse" bordercolor="#000000" width="95%" bgcolor="#364C7D"><tr><td width="100%">This article will show you how to publish your Ruby On Rails applications on a production Linux server using Apache and Mongrel. As well as getting a handle on the technical process involved, you'll also find more information on how to make an educated decision on alternative approaches and advice on how to scale your implementation should the need arise.</td></tr></table></center></td></tr><tr><td valign="top">Body</td><td width="100%"><center><table border="1" cellpadding="3" cellspacing="0" style="border-collapse: collapse" bordercolor="#000000" width="95%" bgcolor="#364C7D"><tr><td width="100%">OK, so you've spent weeks (possibly months) carefully crafting your masterpiece of Rubified simplicity and AJAXy goodness. Your baby is finally ready for release into the public eye, and you're eager to put it out there to see how far it can fly.
>
>Just one problem, but it's a thorny one -– you can't find anybody to host it. You've heard about the pain people have gone through trying to use a shared hosting provider, and the many hours they've spent on the phone to support trying to synchronise Gem versions. On the other hand, setting up your own web server sends shivers down your spine – CGI, FastCGI, SCGI, mod_ruby, mongrel, Apache, and lighttpd are rattling around in your head like the toys you used to play with as a kid. The Rails framework is built on simplicity, so why does hosting it have to be so difficult?
>
>Well, it doesn't. Today, we're going to concentrate on setting up your own web server (because, quite frankly, shared hosting often sucks for performance, and can severely limit your scaling options later on) on a Linux machine. Believe it or not, the choices are really quite simple (and the better solutions are the simplest).
>
>Choosing a strategy
>
>As I said, if you browse around the web you'll find lots of different options for publishing your Rails application under your own steam. In the early days of Rails, the options essentially consisted of running Rails under Apache or lighttpd using mod_ruby, CGI, FastCGI or SCGI to execute your Ruby scripts. Unfortunately, this approach brought with it a number of problems, most notably patchy stability and terrible performance (particularly in the case of CGI, which reloaded the entire Rails framework for each request, although this was partially fixed by the use of FastCGI or SCGI). For this reason, we're not going to consider any of the CGI variants for our server. Similarly, we'll leave mod_ruby to one side for the simple reason that it's no longer in development – it's only been tested up to Rails 1.1, while Rails itself is on 1.2.5 as of October 12, 2007 (the most recent release prior to this article). mod_ruby also has problems with running multiple Rails applications under a single Apache instance due to its use of a shared Ruby interpreter.
>
>Enough of the negative stuff – there's a much happier alternative, going by the name of Mongrel. Mongrel is a very light, relatively quick web server designed to run Ruby-based web applications (Rails isn't the only framework it can run, though). There's a lot of misconceptions about Mongrel, mainly centred around its threading model. The nasty rumour floating around is that it can only handle a single thread at a time, and because it uses one thread per request, that kills its value dead. This isn't true at all – Mongrel itself can handle plenty of requests, although it does start closing connections when it's got too much going on (just like any other web server). No, the problem is Rails itself – Rails doesn't play nicely with threads like the other Ruby frameworks, so a single Mongrel can only execute a single Rails controller action at a time. This can be a bit limiting, but as you'll see, there are ways to beat it.
>
>Just to complicate things a bit (you didn't think this was going to be completely straightforward, did you?), we're going to use Apache as a front-end server to handle static content, so that Mongrel can concentrate on the difficult stuff without juggling images and CSS at the same time. You can use lighttpd instead of Apache, but its reverse proxy plugin has a whole bunch of bugs which cause regular HTTP 500 errors, and nobody appears to be maintaining it any more.
>
>What do I need?
>
>Well, first of all, you'll have to get yourself a server of some description, to which you'll have root access. The cheapest way to achieve this is to pick up a virtual private server (VPS) from one of the many providers out there – there are loads of them, and plenty of reviews. If you're in the USA, there are far more choices than in the UK or Europe, but my advice to you would be to pay careful attention to performance and reliability scores in reviews, since added choices mean greater variation in quality. If you go for a VPS, the lowest specification would have to be 128MB guaranteed RAM with 256MB burstable – the approach we're going to take doesn't need a whole lot more than that, but it can scale to use the resources of considerably more powerful machines should it be necessary (more on that later).
>
>Now that you've got your physical server sorted, you'll need to think about the operating system – if your provider gives you a choice, I'd suggest that you go for Ubuntu 6.06 LTS or Debian Etch, purely because the base repositories already provide most of the software you're going to need to get your Rails infrastructure rolling. If you're more comfortable with one of the Red Hat/Fedora-based distributions, by all means give it a shot; however, be aware that it's going to take more work to get everything up and running.
>
>Disclaimer
>
>I've only tested this process on Ubuntu Server 6.06 (the most recent Long Term Support release, and the version of Ubuntu most likely to be running on your server if you've gone down that route). The same process should work on any later version of Ubuntu, as well as pretty much any distribution based on Debian Etch or later. If you've chosen a Red Hat or Fedora distribution, the process is broadly the same but you might have to substitute package names to fit the appropriate Yum repository. Just a word of caution – I'd recommend against using RHEL 4 or RHEL 5, purely because they have problems with Zlib which may require you to jump through hoops editing the Ruby source code before you compile it. Not a pleasant process, let me assure you.
>
>Getting on with it
>
>Okay, you've got a server, you've chosen your OS, and you're ready to go. First things first – you need Ruby and a couple of extras (you'll need to be root from here on in):
>
>
apt-get install ruby ruby1.8-dev build-essential

>
>Ruby is obvious; ruby1.8-dev is for Mongrel's dependencies later on, and build-essential is for compiling Mongrel's threading extensions and Apache httpd later on. Next, you need to install RubyGems (Ruby's equivalent of apt-get or yum). You may be lucky enough to be able to simply
>
>
apt-get install rubygems

>...try it and see. If not, go to http://rubyforge.org/frs/?group_id=126 and download the latest source tarball (in my case, 0.9.4), then:
>
tar -xzf rubygems-0.9.4.tgz
>cd rubygems
>ruby setup.rb

>
>If you get something like
>
no such file to load -- rdoc/rdoc (LoadError)

>
>...then you'll need to install RDoc, like so:
>
>
apt-get install rdoc

>
>Try it again, and you're set. Also, if you get errors relating to zlib (primarily on Fedora distributions), you'll have to:
>
>
yum install zlib-devel

>
>...then go back to the beginning, compile Ruby from source, and carry on back down the process to this point. Sorry, talk to the Fedora guys about sorting their package manager. Right, we've now got the basics installed. Time to get down to business and make ourselves a web server.
>
>Putting Rails and Mongrel Together
>
>Obviously, we're going to have to install Rails. This is as easy as:
>
>
gem install rails –-remote

>
>This will grab the latest version of the Rails gem from the main repository. If your machine throws something like
>
>
ERROR:  While executing gem ... (Gem::GemNotFoundException)
>
>    Could not find rails (> 0) in any repository

>
>at you, then you'll have to be a little more specific:
>
>
gem install rails -–remote –-version=1.2.4 

>
>(latest version at time of publication)
>Don't panic if you see anything like this in the output:
>
>
lib/action_controller/routing.rb:1098:30: ':' not followed by identified or operator

>
>It's fine – just a bit of documentation on the fritz. We don't read documentation, do we? Next, we install Mongrel, like so:
>
>
gem install mongrel -–remote

>
>Ain't RubyGems great? There may be numerous versions for each dependency, at which point you'll be asked to choose a number – I'd suggest that you pick the latest Ruby-targeted version of each unless you have a very good reason for choosing otherwise (the build target is listed in parentheses after the option e.g. ruby, mswin32).
>
>Up and running
>
>By now, your excitement should be just about reaching fever-pitch. You want to see your site running now, don't you? Worry not, my friend – that's exactly what we're going to try doing now. For this bit, I'm going to use a bare Rails application created like this:
>
>
mkdir /opt/www
>cd /opt/www
>rails test_app

>
>Next, I'll just start the application under Mongrel:
>
>
cd /opt/www/test_app
>mongrel_rails start

>
>Now, use your browser to hit the server on port 3000, and you should see the Rails default welcome page (obviously, if you haven't used a newly-created Rails site, you'll see whatever your site root looks like).
>
>Now, as discussed earlier, the Mongrel-Rails combination goes all single-threaded while it's executing your controller actions; this means that unless your user base is exceptionally well-behaved and is willing to wait in an orderly queue, you're going to need a few more Mongrels to run alongside each other. As it turns out, somebody already thought of this:
>
>
gem install mongrel_cluster

>
>Then, create a file in your application's config directory called mongrel_cluster.yml and put this in it:
>
>
user: root
>
>cwd: /opt/www/test_app/ (or the path to your app's root)
>port: "9000"
>
>environment: development
>
>group: root
>
>address: 0.0.0.0
>
>pid_file: log/mongrel.pid
>
>servers: 3

>
>As you can probably guess, this will run your app as root – you can (and should) change this to any non-privileged user who is able to run your site (disclaimer: you are responsible for your own security here). This file defines a cluster bound to all available local addresses on your machine, with three instances starting at port 9000 (i.e. 9000, 9001, 9002). It also specifies the development environment – you'll change this to production when you're satisfied that everything works. As an example, I tend to run a single Mongrel instance if I'm publishing for somebody to test, or three instances if I don't know what kind of load the site's going to get. I have one site which gets about 60,000 hits per day, and a three Mongrel cluster handles it without a single HTTP 500 error (on a Celeron 2GHz with 512MB RAM). Each Mongrel instance will generally consume around 30MB, as far as I can tell.
>
>Anyway, test your brand new cluster using:
>
>
cd /opt/www/test_app/
>mongrel_rails cluster::start

>
>If you've followed these instructions to the letter, you'll now be able to browse to http://yourserver:9000/, as well as port 9001 and 9002. Since this is a production server, you'll probably want to start all your Mongrels at startup – this is actually pretty easy:
>
>
mkdir /etc/mongrel_cluster
>ln -s /opt/www/test_app/config/mongrel_cluster.yml /etc/mongrel_cluster/test_app.yml
>cp /usr/lib/ruby/gems/1.8/gems/mongrel_cluster-1.0.2/resources
>/mongrel_cluster /etc/init.d
>chmod +x /etc/init.d/mongrel_cluster
>/usr/sbin/update-rc.d -f mongrel_cluster defaults
>(Red Hat/Fedora users should /sbin/chkconfig –level 345 mongrel_cluster on)

>
>What we're doing here is actually future-proofing against additional Rails apps being created on this server – all you need to do to get additional apps to run on startup is to link their config/mongrel_cluster files into /etc/mongrel_cluster, and the startup script will pick them up. It's probably a good idea at this point to reboot your server to test your Mongrel cluster – you don't want to be surprised by a midnight reboot thanks to over-zealous techies at your datacentre.
>
>Using a Real Web Server
>
>Unfortunately for us, the rest of the world doesn't much like specifying port numbers in their web addresses, so we'll have to use a reverse-proxy of some sort to act as a front-end to our Mongrel cluster. As discussed way back at the beginning of this article, you have a whole bunch of choices: for flexibility it's best to go with Apache httpd, for the simple reason that it gives you options of also hosting PHP, Java, mod_perl or practically any other web framework you fancy cobbling together. It's also well-documented and very widely supported.
>
>To get Apache successfully fronting a Mongrel cluster, it'll need to have both mod_rewrite and mod_proxy installed and working. Since we can't really trust our distribution's packaged version, let's just do it from scratch:
>
>
(download latest Apache 2.2 tarball from http://httpd.apache.org/)
>tar -xzf http://mirrors.dedipower.com/ftp.apache.org/httpd/httpd-2.2.6.tar.gz
>cd httpd-2.2.6
>./configure -–enable-rewrite –-enable-proxy
>make
>make install
>/usr/local/apache2/bin/httpd -k start

>
>You should now be able to browse to http://yourserver/ and see the default Apache home page. If not, you probably ignored some errors during the compilation process which you should not have (help compiling Apache is outside the scope of this article). Now that you've tested it, stop httpd:
>
>
/usr/local/apache2/bin/httpd -k stop

>
>To finish the job, we need to persuade Apache to play nicely with our Mongrels. To do this, you'll need to use a text editor and edit /usr/local/apache2/conf/httpd.conf, adding the following to the bottom:
>
>
NameVirtualHost *:80
>
><VirtualHost *:80>
>
>  ServerAdmin support@me.com
>  DocumentRoot /opt/www/test_app/
>  ServerName test_app
>  ServerAlias test_app, test_app.local
>  ErrorLog /opt/www/test_app/log/error.log
>
>  ProxyPass /images !
>  ProxyPass /stylesheets !
>  ProxyPass /javascripts !
>  ProxyPass /favicon.ico !
>  ProxyPass /static !
>  ProxyPass /holding !
>  ProxyPass /templates !
>  ProxyPass / balancer://test_app_cluster
>  ProxyPreserveHost On
>
>  <Proxy balancer://test_app_cluster>
>    BalancerMember http://127.0.0.1:9000
>    BalancerMember http://127.0.0.1:9001
>    BalancerMember http://127.0.0.1:9002
>  </Proxy>
>
>  RewriteEngine On
>
>  # Redirect all non-static requests to cluster
>  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
>  RewriteRule ^/(.*)$ balancer://test_app_cluster%{REQUEST_URI} [P,QSA,L]
></VirtualHost>

>
>This is a fairly simple cluster definition, but what it does is use Apache to serve all your static content, and leaves all the Rails stuff to your Mongrel cluster. To test it, just start httpd:
>
>
/usr/local/apache2/bin/httpd -k start

>
>Have a look at http://yourserver/ to see your Rails application in all its resplendent, load-balanced glory. If you see performance dipping (and particularly if your setup starts refusing connections when busy), you can just add Mongrel instances as you need to – even on different physical servers. Just add them to the proxy cluster definition in your httpd.conf, restart Apache and that's it!
>
>Final Thoughts
>
>What we've done here is pretty good, but it's still got a few small issues. For a start, it won't work for SSL – there are a few workarounds out there, but my experience with this is fairly limited.
>
>Another issue is that of session handling – the default method in Rails is to store session data in the file system. This is all very well, but if multiple Mongrel instances try to access a session's data simultaneously, then you're going to get locking issues. My advice would be to use ActiveRecords to persist session information in the database. This is a fairly simple process, and is detailed in the comments in the default Rails application's config/environment.rb file.
>
>Finally, there's performance. This setup should be able to handle around 100 requests per second, depending on your application and the sheer hardware grunt you have available to you – this is due to the throughput limitations of mod_proxy_balancer in its default setup. There are ways to improve this by tuning your httpd.conf, but that's beyond the scope of this article.
>
>Acknowledgements
>
>I couldn't in good conscience claim that this article is original to me in its entirety – effectively, I started by following the process detailed at http://mongrel.rubyforge.org/, filling in all the blanks, and documenting it in a usable order. I strongly advise you to visit the Mongrel site at RubyForge for more advanced information on Mongrel and its various implementation options.
>
>This article was originally published by CyberArmy.net in the CyberArmy Library.</td></tr></table></center></td></tr></table><br/><br/>




Replies:


Guest:
Subject:
Message:
Signature:
Optional Image Link:
http://

CyberArmy::Forum v0.6
Generated In 0.11955 seconds


About Us | Privacy Policy | Mission Statement | Help