ruby & rails

Magic: Ruby 1.8.5 + 1.9.1/Rails/Sinatra and Lighttpd

Ladies and gentlemen, gather ’round! The Great Panini is going to perform an incredible illusion before your very eyes! You will tell your grandchildren of this day and they will not believe you! Take pictures!

The Great Panini will start with a pre-steam machines era CentOS 4 server. He will install two versions of Ruby and they will coexist peacefully! He will then use the blazing fast Lighttpd server to proxy queries to various Ruby frameworks and he will even make it look easy!

Hrm…Sorry.
I am going to tell you how I quickly updated a couple servers with Ruby 1.9.1 and Lighttpd. And it will look easy because it is, in fact, easy.
This article’s aim is to be practical but I will explain as we go along.

The first thing I did was update CentOS to a more recent version. This could take a while but it’s always a good idea to keep a server software up-to-date so I’m sure that your already are almost there:

yum update

In my case, after a couple hours (oops), the update was complete and I rebooted the servers.

Ruby 1.8.5

That’s the easy part because it’s the version of Ruby that currently comes with CentOS. Therefore you can install it using yum:

yum install ruby ruby-devel ruby-irb ruby-rdoc ruby-ri

Ruby 1.9.1

Download the package from ruby-lang.org:

wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p0.tar.bz2
tar zxvf ruby-1.9.1-p0.tar.bz2
cd ruby-1.9.1-p0

The trick, here, is to give all 1.9.1 binaries a different name. Fortunately, configure offers an option for that:

./configure --program-suffix=19

Build and install:

make && make install

Rubygems

Get rubygems from Rubyforge:

wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz
tar zxvf rubygems-1.3.5.tgz
cd rubygems-1.3.5

Note that we are now using our brand new 1.9.1 binaries:

ruby19 setup.rb

Now, make sure your gems are up to date:

gem19 update

Let’s see. We want to use two frameworks: Rails and Sinatra. Installing them could not be simpler:

gem19 install rails
gem19 install sinatra

We will use thin to run our programs:

gem19 install thin

Let’s make sure that thin is run when the server boots up:

thin install

This will create /etc/init.d/thin which we can then link to the appropriate runlevels using chkconfig

We will, when creating Ruby applications, tell thin about the instances it needs to run. This will be done by adding yml files to /etc/thin/

I am going, in this article, to create these applications in /home/yourdirectory/. Of course, use your own directory.

Rails

Let’s create a Rails application:

rails myrailsapp

In the application’s config/ directory, let’s create our thin yml file (thin_myrailsapp.yml)

chdir: /home/yourdirectory/myrailsapp
address: 127.0.0.1
port: 3000
servers: 4
max_conns: 1024
timeout: 30
max_persistent_conns: 512
user: www
group: www
environment: development
pid: tmp/pids/thin.pid
log: log/thin.log
daemonize: true

chdir tells thin where our document root is located. Rails serves documents from document root/public/
address is localhost because that’s what will be used when proxying through Lighttpd
servers is ‘4′ which means that four servers will be instantiated, starting at , i.e. 3000, 3001, 3002, 3003
User and group: I am using the same user and group that Lighttpd runs as for simplicity sake.

Let’s tell Lighttpd about this new application. Edit /etc/lighttpd/lighttpd.conf, or wherever your configuration file is:

$HTTP["host"] =~ "myrailsapp\.yourdomain\.com$" {
        $HTTP["url"] =~ "^/((images|javascripts|stylesheets)/(.*)$)" {
                server.document-root = /home/yourdirectory/myrailsapp/public"
        }
        proxy.balance = "fair"
        proxy.server =  ("" =>
                (
                        ( "host" => "127.0.0.1", "port" => 3000 )
                )
        )
}

I am using the “fair” load balancer because, as the default option, it tries to be…fair, obviously, and isn’t too greedy: it does not compute a hash for each url.

Let’s now tell thin about this application by simply creating a symbolic link in /etc/thin/:

ln -s /home/yourdirectory/myrailsapp/config/thin_myrailsapp.yml /etc/thin/

Restart Lighttpd and start thin:

/etc/init.d/lighttpd restart && /etc/init.d/thin start

I know…supposedly I should be able to simply type ‘lighttpd reload’ and it will reload its configuration files but that does not always seem to work.

Now, the fun stuff:

Go to http://myrailsapp.yourdomain.com:3000 and you should be greeted by Rail’s welcome page.

Now, go to http://myrailsapp.yourdomain.com and you should see the same page, except this time it was proxyied by Lighttpd.

Sinatra

Create your application; e.g. the ubiquitous “hi” application. Again in /home/yourdirectory/mysinatraapp, create hi.rb:

require 'rubygems'
require 'sinatra'
get '/' do
    'Hello world! I love kittens.'
end

Create a config/ subdirectory:

mkdir config && cd config

In the config/ directory, let’s create our thin yml file (thin_mysinatraapp.yml)

rackup: /home/yourdirectory/mysinatraapp/config/mysinatraapp.ru
chdir: /home/yourdirectory/mysinatraapp
address: 127.0.0.1
port: 4567
servers: 4
max_conns: 1024
timeout: 30
max_persistent_conns: 512
user: www
group: www
environment: development
pid: /home/yourdirectory/mysinatraapp/thin.pid
log: /home/yourdirectory/mysinatraapp/thin.log
daemonize: true

Starting at port 4567 because, by convention, it’s Sinatra’s default port when started standalone.

Notice the main difference? Sinatra will rely on rack for its setup, hence the ‘rackup‘ keyword.
Let’s create that rack file (mysinatraapp.ru)

require 'sinatra'
 
Sinatra::Application.default_options.merge!(
  :run => false,
  :env => :development
)
 
require 'hi.rb'
run Sinatra.application

Do not forget Lighttpd:

$HTTP["host"] =~ "mysinatraapp\.yourdomain\.com$" {
         proxy.balance = "fair"
         proxy.server =  ("" =>
                 (
                         ( "host" => "127.0.0.1", "port" => 4567 )
                         # room for more instances
                 )
         )
}

Of course, if you know that some directories will be dedicated to static content you can also check for these directory names and have Lighttpd serve them statically, as shown in myrailsapp’s example.

Restart Lighttpd and thin:

/etc/init.d/lighttpd restart && killall -HUP thin

Test it:

Go to http://mysinatraapp.yourdomain.com:4567 and you should see the message returned by hi.rb.

Now, go to http://mysinatraapp.yourdomain.com and you should see the same page, except, again. it was proxyied by Lighttpd.

Conclusion

As I wrote earlier, this is easy and actually fairly straightforward. It some of this is not working for you, it is likely because I glossed over something I really shoudln’t have. Post a comment and describe your issue and I will gladly help.

If you enjoyed this post, make sure you subscribe to my RSS feed!


One-line variables swap in PHP, Ruby, Perl, Python and C

Joy in BlueToday’s fun and games: let’s swap a few variables without using more variables than necessary.

Let me know if you disagree with any of this…

$a = 1;
$b = 2;
list($a, $b) = array($b, $a);
print "a=$a, b=$b\n";
a = 1
b = 2
a, b = b, a
puts "a=#{a}, b=#{b}\n"
my $a = 1;
my $b = 2;
($a, $b) = ($b, $a);
print "a=$a, b=$b\n";
?View Code PYTHON
a=1
b=2
a, b = b, a
print 'a=%i, b=%i' % (a, b)

And now, good old C. Let’s use the only method that does not generate an overflow…first, for integer types:

int a=0, b=27;
a=(a^(b=(a=a^b)^b));
printf("a=%d, b=%d\n", a, b);

“Well,” you may say, “but what about pointers arithmetic? Any solution?”
Why, yes. That’s what I came up with after 15 minutes of fiddling:

char *a = "one", *b = "two";
a=(void *)(((long)a)^(long)(b=(void *)(((long)(a=(void *)((long)a^(long)b)))^(long)b)));
printf("a=%s, b=%s\n", a, b);

Note the use of void *, which allows me to ignore the pointer type. And, yes, I know, a C++ compiler may not really like this syntax. This may be doable using templates but I haven’t looked into that.
Sorry, I haven’t looked into Erlang or Haskell yet…

If you enjoyed this post, make sure you subscribe to my RSS feed!


How To Add Ruby/Rails To Your Existing Apache Setup

Rails Logo Still very much in the process of learning Rails myself, I have pretty much mastered the process of running Webrick and Mongrel. Granted, it *is* an easy process.However, I wanted to be able to run my own Ruby applications along my other, mostly PHP-based, applications. That’s where the challenge usually begins. If you use a dedicated server process, you end up having to serve your pages from a non-standard port, such as 3000. This typically does not work for users who are behind a proxy. Additionally, this means that the simplest approach is to ignore virtual servers and run each application on a different port.

I was expecting the RoR Wiki to be helpful. And, overall, it really is; but in this case I found it mostly frustrating, due to some of its information being outdated and not really all that synthetic.

And that is why I decided, inspired by that Wiki, to create my own guide. Note that this guide describes using Ruby with mod_fastcgi.
Note that this guide describes using Ruby with mod_fcgid. I am sure that you’ve read that mod_fastcgi wasn’t working properly and this was a real concern, forcing you to instead use Apache proxying with a regular Ruby server. Not anymore. mod_cfgid fixes all that. No need for an additional server, no need for mod_ruby either.
(more…)

If you enjoyed this post, make sure you subscribe to my RSS feed!