“Run PHP and Ruby on Rails at the same time? Why would you want to do that!?” I can hear you die-hard Ruby developers exclaim.

Lots of reasons actually. There is an enormous amount of good PHP code out there, and you might like to use some of it someday. For example, I’m integrating the wonderful TinyMCE editor into Moral Metric using the TinyMCE plugin (read John Wulff’s how-to). TinyMCE runs flawlessly with Rails, and it’s very easy to set up. But I needed to use the spellchecker extension, which is written in PHP. Having no desire to port a PHP script to Ruby when it works just fine in PHP, I decided that there must be some way to make these PHP scripts work from within my Rails application.

As it turns out, it’s sublimely easy to set up.

Naturally, you’ll need a working Rails application to try this. You’ll also need lighttpd for this to work. And you’ll need to have PHP installed and compiled with FastCGI support (see the lighttpd manual for more information).

My Lighttpd installation is configured as my primary web server, listening on port 80. Since I have several websites hosted on my server, I use mod_proxy to proxy incoming requests to the appropriate port. Then I have an instance of Mongrel running on some other port for each website. So for example, if you go to www.crossconnector.com, Lighttpd would receive the request on port 80 (the normal port for www requests), and proxy the request to port 7500. Here’s an example from my lighttpd_proxy.conf file:


# CrossConnector Example
$HTTP["host"] =~ "(^[w]*\.)crossconnector\.(com|org|dev)" {
  proxy.server = ( "" => ( "crossconnector" => ( "host" => "127.0.0.1",
                                                "port" => 7500)))
}}

There are two fun things to notice here. First, this configuration lets crossconnector.com respond to any number of w’s in the address. Try it! crossconnector.com/, w.crossconnector.com/, and wwwwwww.crossconnector.com/ all work. That’s because of the (^[w]*\.) in the $HTTP["host"] conditional statement, which is a regular expression that says “match any number of w’s, even zero”.

The second fun thing is the code (com|org|net|dev). This allows the web server to respond to any of the top-level domains (TLDs) that we have for CrossConnector. So www.crossconnector.com/ and www.crossconnector.org/ both pull up the same page. What about .dev? Is that some new TLD that they forgot to tell us about? No, it’s my little internal domain. I’ve modified my /etc/hosts file to automatically forward www.crossconnector.dev to the proper IP address on my development server. That way I don’t have to remember any icky IP addresses, and it makes the testing experience much nicer to see a proper domain name instead of an IP.

Back to business. I’ve also configured Lighttpd to respond to requests for PHP files. Earlier in my lighttpd_proxy.conf file, I have this block:


fastcgi.server = ( ".php" => ((
                    "bin-path" => "/usr/local/bin/php",
                    "socket" => "/tmp/php.socket")))

This just tells Lighttpd where to find the PHP executable file, and where the socket should be. Again, refer to the Lighttpd documentation. Not much to see here. Let’s move on.

Now, here is where the action happens. I want to set up my site so that any PHP files will get handled by PHP instead of Ruby. To do this, I use Lighttpd’s conditional statements to exclude web pages that end in .php. My conditional statements block receives requests for the exitingnewproject.com domain, and proxies everything to the Rails app running on port 7600. Everything, that is, except PHP files, which it handles without proxying. To make sure that the server is serving the right PHP files, I set the server.document-root variable to look at the root of my Rails app. Here’s the snippet from lighttpd-proxy.conf:


# PHP inside Ruby Example
$HTTP["host"] =~ "(^[w]*\.)exitingnewproject\.(com|org|net|dev)" {
  $HTTP["url"] !~ ".php"{
    proxy.server = ( "" => ( "exitingnewproject" => ( "host" => "127.0.0.1",
                                                "port" => 7600)))
  }
  $HTTP["url"] =~ ".php"{
    server.document-root        = "/srv/app/exitingnewproject/public" 
  }
}

Now all I have to do is drop a .php file into the Rails app’s /public directory, and voila! – PHP works, including TinyMCE’s spellchecker

Links in this article:


3 Responses to “Combining Ruby on Rails and PHP with Lighttpd Magic”

  1. Nathan Smith Says:
    Or... You could just use PHP instead of Rails (oh, did I just say that). Just kidding, good tips there Ryan.
  2. Ryan Says:
    Bleah.... PHP. We have no use for that here. ;)
  3. Jim Says:
    I thought PHP and Ruby is an impossible mix. Strange thing...

Leave a Reply