Looking for the Ultimate Ruby on Rails Hosting Stack?
Rails is an incredibly popular web development framework. It can be a bit tricky to setup. And it requires an environment that many standard 'shared hosting' plans cannot provide.
To quote one recent RimuHosting VPS customer 'Rails on shared hosting sucks!'.
With a VPS setup you are more in control and you can setup a RoR hosting stack that suits your needs exactly.
All the Tools You Need. The RimuHosting Ruby on Rails Hosting Stack
Here at RimuHosting we have come up with a setup that should get you off on the right foot. It is the RimuHosting Ruby on Rails Hosting Stack. It includes:
- Ruby 1.8.6
- Rails 2 (or if you need the 'older' 1.2 just mention that)
- Sample rails app at /var/www/test
- gem. So you can gem install xxx whatever you need.
- mysql ruby bindings. e.g. see echo "require 'rubygems'; require_gem 'mysql'" | irb
- rmagick ruby bindings. e.g. see echo "require 'rubygems'; require_gem 'rmagick'" | irb
It then sets things up so that you can run rails apps via apache, lighttpd or mongrel.
If you are after this setup, just mention 'Please install the RimuHosting Ruby on Rails Hosting Stack' on the order confirmation page when/if you order a RimuHosting server (at
http://rimuhosting.com/order/startorder.jsp)
For a RoR server we recommend you go with a VPS with 128MB of memory or more (since rails can be somewhat memory hungry).
Preferred Distros For Rails Hosting
The preferred distro for Rails hosting is one that supports Apache 2.2. Since this has mod_proxy_balancer support. Which works in well with the Apache + Mongrel setup.
FC5, FC6, FC7, Centos5, Ubuntu Gutsy, Debian Etch all come with Apache 2.2.
RHEL4, Debian Sarge, Ubuntu (Eft and Dapper) are all Apache 2.0 based.
We have installed rails these distros. But with Apache 2.0 they do not have mod_proxy_balancer. Which imposes some (probably livable) restrictions on your setup.
Running Rails With Mongrel
Mongrel is an up and coming rails-specific web server. See
http://mongrel.rubyforge.net If you are considering running lighttpd then mongrel looks like it would be a good alternative to that.
After the RimuHosting rails stack is installed there will be a sample mongrel init script in /etc/init.d/mongrel that will stop/start a mongrel process.
Notes:
Using Apache as A Front End To Mongrel or Lighttpd
Try adding the following to your Apache 2.0 Virtual Host directive:
Note: Remove any '>>' characters that the html on this page adds to that url if you copy/paste it.
(Still waiting to confirm this bit works, and it is likely different with apache 2.2).
Using Apache 2.2 with mod_proxy_balancer As a Front End to Mongrel Cluster
The Ruby on Rails dispatcher can only handle one request at a time. It is 'synchronized' to only let one through at a time. Why? Since it is not designed to run multiple threads simultaneously.
For most non-slashdot-sized sites this is fine. Since requests can execute quite quickly.
If you have a busier site though, Apache 2.2 has a new option for you. It offers the mod_proxy_balancer module. This lets you run multiple rails instances and then use the proxy balancer to spread your requests over multiple rails containers.
The downside is higher memory usage (so you'd need a server with more memory).
The 'balanced' rails setup would look like this:
Start your mongrels:
mongrel_rails start -d -e production -p 8000 -a 127.0.0.1 -P log/mongrel.8000.pid -c /var/www/test
mongrel_rails start -d -e production -p 8001 -a 127.0.0.1 -P log/mongrel.8001.pid -c /var/www/test
(Or modify /etc/init.d/mongrel).
Then setup an Apache 2.2 (it does not work in Apache 1.3 or 2.0) virtual host:
<VirtualHost *:80>
ServerName dummy-host.example.com
# Presuming your rails app is at /var/www/test
DocumentRoot /var/www/test/public
<Directory "/var/www/test/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory> # Configure mongrel_cluster
<Proxy balancer://mongrel_cluster>
BalancerMember
http://127.0.0.1:8000
BalancerMember
http://127.0.0.1:8001
</Proxy> ProxyPass / balancer://mongrel_cluster/
ProxyPassReverse / balancer://mongrel_cluster/ # These directories should always be served up by Apache, since they contain static content. Or just let rails do it.
ProxyPass /images !
ProxyPass /stylesheets !
ProxyPass /javascripts !
ProxyPass /favicon.ico ! RewriteEngine On # Important rule to prevent exposure of subversion files if you are deploying with Capistrano !
RewriteRule ^(.*/)?.svn/ - [F,L] # Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA] # Rewrite to check for Rails cached page
RewriteRule ^([^.]+)$ $1.html [QSA] # Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
</VirtualHost>
Running Rails With Lighttpd
There are a few options when it comes to choosing a 'front end' web server to your rails app. Choices include Mongrel or Lighttpd.
Lighttpd is standalone web server. It is commonly used (or at least requested) by the rails community. You can use it to run rails apps.
After the RimuHosting rails stack is installed there will be a sample lighttpd init script in /etc/init.d/lighttpd that will stop/start a lighttpd process.
Note:
- Lighttpd would run on port 3000. You could run it on port 80. That would prevent you running apache on that port. Else you'd need a different/extra IP.
- We have not setup ssl with lighttpd before. Not sure what's involved there.
To run lighttpd with multiple domains you would setup virtual hosting. e.g. in lighttpd.conf:
$HTTP["host"] =~ "(www.)?example.com" {
server.document-root = "/var/www/example/current/public/"
server.error-handler-404 = "/dispatch.fcgi"
fastcgi.server = (
".fcgi" => (
"localhost" => (
"socket" => "/var/run/www/example.com-0.socket"
)
)
)
} $HTTP["host"] =~ "(www.)?example2.com" {
server.document-root ="/var/www/example2/current/public/"
server.error-handler-404 = "/dispatch.fcgi"
fastcgi.server = (
".fcgi" => (
"localhost" => (
"socket" => "/var/run/www/example2-0.socket"
)
)
)
}More info at
http://www.lighttpd.net/documentation/configuration.html
Using Apache 2.0 with a load balancing proxy As a Front End to Mongrel Cluster
Apache 2.0 does not have mod_proxy_balancer as part of the module listing. Upgrading the stock distribution's Apache installation cannot proceed though without having to recompile all applications that link to libapache (e.g. PHP, etc). However, an alternative solution to mod_proxy_balancer would be the use of a third-party application that would do the load balancing of the rails processes in a mongrel_cluster.
Popular choices that can be used as the load-balancing proxy server for mongrel_cluster include Pound (
http://www.apsis.ch/pound) and Pen (
http://siag.nu/pen).
Getting 'client denied by server configuration' Errors
If you're getting errors like this:
Check that you have something like this in your httpd.conf:
<Proxy *>
Order allow,deny
Allow from all
</Proxy>
In Debian and Ubuntu, this is set to
deny by default in /etc/apache2/mods-available/proxy.conf.
The RimuHosting Rails Stack Script
To run the RimuHosting Rails Hosting Stack script:
wget -O rails.sh "http://proj.ri.mu/rails.sh"
bash -x rails.sh
You can view a html-ized the RimuHosting Ruby on Rails Hosting Script at
http://downloads.rimuhosting.com/miscproj/rails.html (this is likely not the most recent version).
The script is updated by us every now and then if we find it stops working for whatever reason. If you find a problem with it or have a suggestion then email p.bliki.rimuhosting.com at rimuhosting.com and let us know and provide a 'patch' if you can.
Caveats: No warranty express or applied. We take all care but will not be liable for any problem. We recommend you use the script as a guide. Do not 'just run' it. It may format your hard drive, and electrocute your mother. Seriously: it could potentially break your existing ruby/gem/apache/lighttpd/mongrel setup. Look at the code carefully before running any of it on your system.
The code will 'error out' if/when it hits problems and stop at that point. We are interested in any changes that would help us run the script on a wider variety of distros and handle a wider variety of conditions.
Stale PID files preventing Mongrel to start up
If you get these messages when trying to start mongrels, that's because it's not cleaning/ignoring PID files properly:
# /etc/init.d/mongrel_cluster start
Starting all mongrel_clusters…
** !!! PID file log/mongrel.8000.pid already exists. Mongrel could be running already. Check your log/mongrel.log for errors.
** !!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start.
** !!! PID file log/mongrel.8001.pid already exists. Mongrel could be running already. Check your log/mongrel.log for errors.
** !!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start.
** !!! PID file log/mongrel.8002.pid already exists. Mongrel could be running already. Check your log/mongrel.log for errors.
** !!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start.
Thanks to the patch provided here
http://textsnippets.com/posts/show/931 you should be able to avoid that problem. Save this file as "/tmp/mongrel.patch":
--- bin/mongrel_rails-orig 2007-05-16 14:41:51.000000000 -0400
+++ bin/mongrel_rails 2007-05-16 14:42:50.000000000 -0400
@@ -83,9 +83,17 @@
config = Mongrel::Rails::RailsConfigurator.new(settings) do
if defaults[:daemon]
if File.exist? defaults[:pid_file]
- log "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors."
- log "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start."
- exit 1
+ # mongrels that crash can leave stale PID files behind, and these
+ # should not stop mongrel from being restarted by monitors…
+ pid = File.new(defaults[:pid_file]).readline
+ unless `ps -ef | grep #{pid} | grep -v grep`.length > 0
+ # use "ps ax" for freebsd
+ log "!!! PID file #{defaults[:pid_file]} exists, but is stale, and will be deleted so that this mongrel can run."
+ File.delete(defaults[:pid_file])
+ else
+ log "!!! PID file #{defaults[:pid_file]} already exists and the process id referred to in it is running. This mongrel is probably already running. #{defaults[:log_file]} for errors. EXITING."
+ exit 1
+ end
end daemonizeThen apply it by running something like this:
- patch -p0 /usr/lib/ruby/gems/1.8/gems/mongrel-1.0.1/bin/mongrel_rails < mongrel.patch
Internal Server Errors when using Internet Explorer
If you're getting Internal Server Errors from Apache when using Internet Explorer to connect to SSL pages, see if this KB article seems to match your problem:
http://support.microsoft.com/default.aspx?kbid=831167If so, the fix is to use the following in your SSL virtual host:
SSLOptions +StdEnvVars
BrowserMatch ".*MSIE.*"
nokeepalive ssl-unclean-shutdown
downgrade-1.0 force-response-1.0
Taken from:
http://www.freeonrails.com/node/17784
Mongrel Cluster not starting up at boot
Even though you symlinked the mongrel_cluster init script to the right rc.d directory, it's not starting correctly. In the console you might see something like this (on Centos5):
Starting mongrel_cluster: which: no mongrel_cluster_ctl in (/sbin:/usr/sbin:/bin:/usr/bin)
[ OK ]
Add this PATH variable to /etc/init.d/mongrel_cluster:
CONF_DIR=/etc/mongrel_cluster
PATH=/usr/local/bin:$PATH
RETVAL=0
The next time you boot, on the console you should see this:
Starting mongrel_cluster: Starting all mongrel_clusters…
[ OK ]
We've seen this on Centos5 and Ubuntu a few times.