@madpilot makes

Running Passenger on Joyent

I’ve never been particularly happy with proxying Mongrel processes behind Apache – for one if makes it really hard to scale without using something like God (which adds yet ANOTHER process your website is dependent on) and having separate services means multiple points of failure.

PHP has had mod_php which makes PHP a first class citizen in Apache land, and with the release of Passenger (aka mod_rails) a couple of months ago Rails can now get the same privileges. As most of my production Rails apps (both for me and my clients) run on Joyent, here is a quick recipe for setting up passenger on the newer pkg-src accelerators. You need to be root to do a lot of this, so it might be easiest to


before you start.

  1. Getting passenger. DON’T use the gem, as it won’t work on Solaris – you need to pull it from git (I think it makes sense to put it in /usr/local):
    cd /usr/local
    git clone git://github.com/FooBarWidget/passenger.git
  2. Run the apache module installer:
    cd passenger/
  3. Create a configuration file for apache:
    cd /opt/local/etc/httpd
    echo "LoadModule passenger_module /usr/local/passenger/ext/apache2/mod_passenger.so
    PassengerRoot /usr/local/passenger
    PassengerRuby /opt/local/bin/ruby18" > includes/passenger.conf
  4. Add the following line to /opt/local/etc/httpd/httpd.conf:
    Include etc/httpd/includes/passenger.conf
  5. Make Apache a little less strict on what it can run. Open /opt/local/etc/httpd/includes/directory.conf and change the Directory directive to (Apache security geeks will probably lynch me at this point – please suggest a more secure setup):
    Options +FollowSymLinks -SymLinksIfOwnerMatch +MultiViews -Indexes -ExecCGI
    AllowOverride ALL
    Order allow,deny
    Allow from all
  6. Restart Apache:
    svcadm restart /network/http:apache

At this point Apache will be mod_rails enabled. Now to update your application. There is two ways to do this: manually or via the Joyent capistrano receipe. I’ll outline the latter, and you should be able to work out the former for these instructions (Hint: the virtual host descriptions are in /opt/local/etc/httpd/virtualhosts/). Edit config/accelerator/apache_vhosts.erb and find the VirtualHost directive and make it look something like this:

<VirtualHost <%= public_ip %>:80>

  ServerName <%= server_name %>

  RailsBaseURI /

  DocumentRoot <%= public_path %>


Then run

cap accelerator:create_vhost

followed by

cap accelerator:restart_apache

If all went well, your site should be now running via passenger! If all is well, we should remove the mongrel service and update our capistrano receipe, as the restart options are now different. To remove the the mongrel config, run cap accelerator:smf_delete. Finally open config/deploy.rb and remove the start and stop deploy tasks, and replace the restart task with:

deploy.task :restart do

  run "touch #{current_path}/tmp/restart.txt"


That should be it. Next time: How to do it on the older Joyent accelerators.

WGET: The poor man’s SVN – Using Capistrano on a host with out subversion

I have a client for whom I created a CakePHP-based website for over a year ago. He has since come back to me and asked for a number of changes. I thought I would take the opportunity to use capistrano, because there are a number of steps I always had to perform when updating his site and I hate having to do them manually.

I went about checking all the necessary requirements on his host:

  1. SSH access – check! The host his site was on allows an SSH connection which is required by capistrano
  2. Apache follows symbolic links – check! Because capistrano uses a symbolic link from the document root to the latest version of the site, Apache needs to be able to follow them (i.e the site’s apache configuration needs FollowSymLinks enabled)
  3. Has svn installed – fail! This could be a problem. Capistrano by default checks out the HEAD revision from the defined repository – if it can’t use SVN, it can’t download the latest version of the site.

So close! If only I could download the HEAD revision of a site using a common command line system. I thought about writing a SVN-to-web interface, that would check out the latest version and post them as a website, but then I remembered SVN does that out of the box using the SVN apache module. Thankfully, when I was building my development machine, I made I installed the SVN module – it was now time to use it!

First I needed to tell Apache serve up the a copy of the SVN repository. Dropping the following into the Apache config file did the trick:

  1. <location /url/you/would/like/to/access>
  2. DAV svn
  3. SVNPath /path/to/svn/repository
  4. AuthType Basic
  5. AuthName “My Secret SVN Repository”
  6. AuthUserFile /path/to/a/.htpassword/file
  7. Require valid-user
  8. </Location>

For those playing at home, replace /url/you/would/like/to/access with a nice easy path – this is the URL you will access to download the files, replace /path/to/svn/repository with the actual physical path to your repository and create a .htpassword file so you can limit access to the repository by using the htpasswd2 command: htpasswd2 -c /path/to/a/.htpassword/file username would work in this case (After substituting a username and real path, of course)

If you point you browser to the URL you just setup, you should see the root directory of the repository, after you enter the username and password you setup. Congratulations! You are basically there. Now you just need to reconfigure your capistrano to use wget instead of svn. I do this by overriding the deploy method – because I’m not using rails for this project, the paths and shard folders are different anyway. If you are using rails, you might need to have a look at the original recipe file and replace the svn command with the one below.

  1. task :deploy do
  2. run “wget –user=#{wget_user} –password=#{wget_pass} -m –cut-dirs=4 -nH -P #{release_path} -q -R index.html #{repository}”
  3. run “ln -nfs #{release_path} #{current_path}”
  4. run “rm -rf #{release_path}/app/webroot/files”
  5. end

The only modification to that line is the number after the –cut-dirs switch – it should be equal to the number of directories in the URL. In our example the URL is /url/you/would/like/to/access so –cut-dirs it needs to be equal to 6.

The last thing to do is to setup the wget_user and wget_pass variables to be equal to the username and password you created using htpasswd2.

That should do it! You can now deploy to a server that is sans SVN!

Caveats: Because of the way the SVN module and WGET work, I’ve had to not include he downloading of index.html (Basically WGET treats the directory listing as a page, and will output it as index.html) so this technique will not work if you have any pages called index.html in your structure. Work around: Rename all instances of index.html to index.htm

You might get some weird results if some one checks in code at the same time as you do a deploy – unless you have a bucket load of developers working on your system and you have no communication between developers, this is pretty unlikely.

(Names have been changed to protect the innocent)