Handle it, Handle it 2

Posted by smoe Mon, 15 Jun 2009 17:16:00 GMT

I don't want my applications to throw exceptions. Not every un-handled exception can be exploited, but if you want to crack a web application that's a good place to start.

Who Moved My Gems?

Posted by smoe Fri, 22 May 2009 20:13:00 GMT

I appreciate the tough decisions the guys at Phusion had to make. Distributing products like Ruby Enterprise Edition and mod_rails is a lot of work. It's got to run on dozens of different operating systems and Linux distributions, every one with it's own package manager and configuration preferences. They did a great job of it. Their install script is the best of it's kind that I have seen, and I applaud their decision to use /opt, they are using that directory for it's intended purpose.

The problem is that the executable files in /opt/ruby-enterprise/bin are not in the default path, and it's a lot of keys to type /opt/ruby-enterprise-1.8.6-20090421/bin/ every time you want to run rake or rails or any other gem based executable. This is not a problem for your production application. Once you have Apache configured to load Passenger it knows where to find all the gems, but in development or deployment you may experience pain.

I have been around and around on this problem. At first I just typed in the whole /opt path, when I remembered too, and used the regular version of gems and Debian's ruby1.8 when I forgot. When I set up some new servers with REE and passenger from the start with no other ruby interpreter on the machine I knew I needed to stop winging it. I could have just run a parallel installation with ruby1.8 and all the gems installed twice, once for Apache and once for the command line, but I found that unappealing.

I did not test the first version of this post well enough. I had thought I solved the problem by changing the PATH environment variable so /opt/ruby-enterprise/bin was the first place searched for executables, but there are situations when that just does not work.

For example: you will need to run rake as a normal user during development, with sudo when you install gems specified in environment.rb, as root if you su – to work through a new installation or a system upgrade, as a non-interactive user when you deploy with capistrano, and with sudo via capistrano. I changed /etc/profile, /etc/environment, /root/.bashrc, ~./bashrc, and aliased sudo but I still couldn't get every situation to work correctly. I need to warn you in particular about using an alias for sudo as I showed in the first version of this post. It removed the sbin directories from the PATH you get with sudo and system commands cannot be found.

One thing I had tried early on was to use /etc/alternatives. It was tedious to run update-alternatives by hand and every new gem could add a new executable and when Phusion released a update to REE I had to do it all over again.

My new approach goes back to /etc/alternatives and, so far so good, it seems to solve all these problems. If you are running Ubuntu and installed REE from Phusion's .deb you will already have a /opt/ruby-enterprise directory. If you are running Debian you can create a link by that name to the current release of REE. Then we can depend on /opt/ruby-enterprise being the current release. When a new version comes out just update the link and you should be ready to go. This is how I create the link for Debian.

$ sudo ln -s /opt/ruby-enterprise-1.8.6-20090421 /opt/ruby-enterprise

Now to automate the chore of creating the /etc/alternative links. I just did a rake task because it simplifies a few things, but it is just a simple loop and it could be done as a real script someday.

namespace :ree_alt do
  desc 'find ruby-enterprise-edition executables and link as alternatives'
    task :install do
      Dir.entries("/opt/ruby-enterprise/bin").each do |executable|
        unless [".", ".."].include? executable
          `update-alternatives --install /usr/bin/#{executable} #{executable} /opt/ruby-enterprise/bin/#{executable} 100`
        end
      end
    end

desc 'remove all ruby-enterprise based alternatives'
  task :remove do
    Dir.entries("/opt/ruby-enterprise/bin").each do |executable|
      unless [".", ".."].include? executable
        `update-alternatives --remove-all #{executable}`
      end
    end
  end
end

As usual there is plenty of room for improvement. When you need to update the alternatives what you have to do is run the remove task and then run the install task, with sudo. Trick is when you run install you will not have rake in your path so you need to go back to the long /opt path name.

$ sudo /opt/ruby-enterprise/bin/rake ree_alt:install

So it's not beautiful, but it does work this time, and it's not too much of a chore.

The Crime of Offending

Posted by smoe Fri, 01 May 2009 14:25:00 GMT

I was not at GoGaRuCo, I really don’t know what it was like to sit through Matt Aimonetti’s presentation, and I surely don’t know what it would have been like to be a woman in that room. So I feel quite confident in stating that I think everybody is wrong. As humans our natural condition is be incorrect while we puff up, posture, and strut about indignantly. Follow along while I demonstrate.

Matt gave a presentation to our local users group, ORUG, last year after RubyConf. It was an interesting talk on framework performance and I took away some useful information. He followed a talk by Thomas Meeks on Nanite, which was a lot more interesting and memorable. I don’t blame Matt for looking for a way to make his talk edgy and provocative. I have seen the slides from Matt’s talk at GoGaRuCo, apparently with the most salacious three images removed, and it didn’t do anything for me. I’ve seen episodes of South Park that made me way more uncomfortable than any of those pictures. I suspect the real problem was reaction of the audience. A gang of aroused juveniles is more intimidating than any image.

If you felt the images were worth an NC-17 rating while the next guy says R or PG-13 is not the point. There is certainly room for edgy humor in a technical talk, it can even be helpful, but there is no need for distracting puerile imagery. That said, if you are offended by a person, it’s your problem, not theirs. Get up and walk out, turn off the television, block the twitter account, blacklist the email address, just don’t whine that others need to accommodate your sensitivities. Personally I am offended when someone claims their state of being offended requires others to change their ideas, language, or culture. It makes for a vicious cycle of intolerance for the intolerant. If we are going to get along we need to accept that everyone has the right to be as wrong and offensive as you.

My Apache Configuration for Ruby on Rails with Passenger

Posted by smoe Sat, 18 Apr 2009 12:20:00 GMT

One of the great things about using Passenger rather than Mongrel is the simple Apache configuration that gets you started. You don’t need to manage ports, decide how many processes an application is going to need, or edit a second configuration file for the application servers. At this time passenger 2.2.0 is the newest release, and it works great with mod_rewrite and every other Apache module I use.

This is the virtual host entry from the Phusion Passenger Apache Users Guide


<VirtualHost *:80>
    ServerName www.mycook.com
    DocumentRoot /webapps/mycook/public
</VirtualHost>

It couldn’t get much simpler and it could be all you need, but my development environment requires a bit more. The first change is something I believe I picked up from a PeepCode screencast. Edit your etc/hosts file to add a name for any site you are developing. it might look like this:

 

127.0.0.1    localhost newsite.local oldsite.local

Then you can see the sites in development on your local machine with http://newsite.local. Another great thing about Passenger is that it automatically runs as the user that owns the site. So you can keep all your log files, including Apache’s access and error logs, under your home directory and view them without fussing with sudo. With this next Apache configuration I can access any of my local sites quickly and keep the log files separate. I don’t’ think you need a LogLevel more verbose than "warn", we are not debugging Apache, just a website. You shouldn’t see "smoe" in your Apache configuration, that’s my actual username and work directory. I am not worried about publishing it because I always use awesome high quality passwords and RSA certificates.


<VirtualHost *:80>
    ServerName newsite.local
    DocumentRoot /home/smoe/work/newsite/public
    LogLevel warn
    CustomLog /home/smoe/work/newsite/log/access.log combined
    ErrorLog  /home/smoe/work/newsite/log/error.log
</VirtualHost>

I love working in Debian. It’s default apache2 configuration allows you keep a separate file for every virtual host and enable or disable them very quickly. When I setup a new site I just make a copy of an existing site and change the name. This is what I have to type.

sudo cp /etc/apache2/sites-available/oldsite /etc/apache2/sites-available/newsite
sudo vi newsite
:1,$s/oldsite/newsite/
:wq
sudo a2ensite newsite
sudo /etc/init.d/apache2 reload

That is really all it takes to run a development server. I need a bit more for staging and production. A staging servers should be configured exactly like the production server. I use the label "preview" in my database.yml file and I set up deploy.rb in Capistrano to deploy to preview by default. For a production deployment I have to type RAILS_ENV=production on the cap deploy command line. I don’t want to accidentally deploy to production. I could go on but the details of Capistrano and staging servers are off topic.

Production servers have additional requirements for their Apache configuration. Mine uses mod_rewrite to support cap deploy:web:disable. I had a nice hack for older versions of passenger but we don’t need that anymore. I also use mod_deflate and mod_expires to improve site performance. If you want to understand why check out the YSlow firefox plugin. Again Debian makes your Apache configuration a breeze. Run a ls on /etc/apache2/mods-enabled if you don’t see deflate and expires just type this:

sudo a2enmod deflate
sudo a2enmod expires
sudo /etc/init.d/apache2 restart

Now we are ready for my ultimate production Apache2 configuration. I had some problems getting ExpiresbyType to work, but putting ExpiresDefault in a <FilesMatch> container works fine, and it handles subdirectories I was missing with a <Directory> container. There might be a way to make this configuration smaller, but I’d rather be done than perfect. Don’t forget to set your RaisEnv. The default is development, and we are doing preview or production here. We also configure Etags to none so Rails can handle the Etags,


<VirtualHost *:80>
    ServerAdmin smoe@newsite.com
        ServerName www.newsite.com
        DocumentRoot /home/smoe/newsite/current/public

        RewriteEngine On
        RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
        RewriteRule ^.*$ /system/maintenance.html

        RailsEnv preview

        ExpiresActive on

        <Directory /home/smoe/newsite/current/public/>
                Options -Indexes
                AllowOverride None
                Order deny,allow
                Deny from none
                Allow from all
                AddOutputFilterbyType DEFLATE text/html
                FileEtag none
        </Directory>

        <FilesMatch "\.(js|css|gif|png|jpg)$">
                ExpiresDefault "access plus 2 year"
                SetOutputFilter Deflate      
        </FilesMatch>

        LogLevel warn
        ErrorLog /home/smoe/newsite/shared/log/error.log
        CustomLog /home/smoe/newsite/shared/log/access.log combined
</VirtualHost>

Now you’re serving up a high performance Ruby on Rails with Passenger web application.

Deploying with git submodule 1

Posted by smoe Mon, 13 Apr 2009 17:26:00 GMT

I’ve been busy upgrading servers to Passenger 2.1.3 and trying out Rails 2.3.2. One nifty feature is rails-templates. You can write a simple template that lets you create new rails projects with all your favorite plugins and gems automatically installed, you can install the CSS and JavaScript you like, and change all the default files to suit your purpose, all with the one rails command line. This probably saves an hour or more per new project and gives you a consistent setup.  My rails-template is published at  http://zipi.github.com/rails-templates/, I may have gotten a little carried away with it, but I like it.

One thing I learned to do while writing my template is to use git submodule. When you install a plugin from a git repository you can specify it be installed as a submodule. This way the plugins are not included in your new project’s repository. The first lesson was when I cloned a project to my laptop so I could work on the road. The application wouldn’t start up because the plugin directories were empty. Before I could run the application I had to run some more git commands

git submodule init
git submodule update

It took longer to learn what I needed to do than it took to do it. Good thing I saw this problem on my laptop, because when I deployed to a staging server I saw it again and knew what to do. I shelled in, cd to the release directory and ran the git submodule commands. Easy enough but I can’t do that every time I push a new version.

So I have a new recipe for my deploy.rb file to be called after update.

desc "Install git submodules"
task :git_submodules do
  run "cd #{release_path} && git submodule init"
  run "cd #{release_path} && git submodule update"
end

task :after_update_code do
  # other tasks here
  git_submodules
end

It works. And that is about all I can say about it. It’s slow and silly to clone rspec in order to deploy to a production server where you will never run rspec. I also prefer to have the same specific version of a plugin I use in development to be used in production.

Maybe using git submodule for plugins is not really a good idea after all.

acts_as_conference 1

Posted by smoe Fri, 19 Dec 2008 00:37:00 GMT

I’ll be there. So should you.

cap deploy:web:disable and Phusion Passenger (final update) 6

Posted by smoe Thu, 09 Oct 2008 20:17:00 GMT

This may still be useful to people in a shared hosting environment, but If you are administering your own server this hack is obsolete. As of Passenger 2.1.1 mod_rewrite is fully supported, or so I am told, I’ll try it out soon.
 
When you switch from mongrel to Passenger you will see many improvements. The web sites are faster, configuration is simpler, and deployment is easier. With the Passenger Apache module handling Ruby on Rails there are no separate application server processes, no proxy server calls, and you don’t need mod_rewrite for static content.
 
The only thing you lose are some Capistrano recipes: cap deploy:stop and cap deploy:web:disable will not work. I can live without deploy:stop. I don’t want my users to see "no response from server" or "upstream proxy server error" or any other error message that looks like something blew up. That’s why I like deploy:web:disable. I wish I never needed it but if something does go wrong, or a database needs to be reloaded or re indexed, deploy:web:disable is nice to have. The default maintenance.html page is a clean, simple message that shows you are in control. Problem is when you lose mod_rewrite you lose the mechanism that instructed Apache to skip the web app and show the maintenance page.
 
I’ve seen reports that you can set RailsAllowModRewrite on and only use mod_rewrite for the maintenance page, but it didn’t work for me. As far as I can tell Passenger and mod_rewrite just don’t work together. Passenger does a good job with static content so I don’t miss mod_rewrite, and it is still available to virtual hosts that are not Ruby on Rails applications.
 
What I came up with is a before_filter for the application controller. It’s not exactly the same thing. The application still needs to start up and serve the maintenance page, but if this is the first before filter there should be no database access and you can do almost anything you would do with a mod_rewrite disable.
 

To make it easy to copy around I put this mix-in module in lib/maintenance_mode.rb

module MaintenanceMode
protected
  def disabled?
    maintfile = RAILS_ROOT + "/public/system/maintenance.html"
    if FileTest::exist?(maintfile)
      send_file maintfile, :type => 'text/html; charset=utf-8', :disposition => 'inline'
    end
  end
end

And make these the first two lines in class ApplicationController, before any before_filters that might access the database.

  include MaintenanceMode
  before_filter :disabled?

And that’s all it takes to get cap deploy:web:disable to work again. This is the bit of code I put at the end of config/deploy.rb to replace start, stop and restart, and provide some handy Capistrano recipes for working with passenger.

namespace :deploy do
 desc "Restart Application"
 task :restart, :roles => :app do
   run "touch #{current_path}/tmp/restart.txt"
 end

 desc "Not used with Passenger"
 task :start, :roles => :app do
   # nothing
 end
 desc "Not used with Passenger"
 task :stop, :roles => :app do
   # nothing
 end
end

namespace :passenger do
 desc "passenger memory stats"
 task :memory, :roles => :app do
   run "passenger-memory-stats" do |channel, stream, data|
   puts data
 end

 desc "passenger general info"
 task :general, :roles => :app do
   run "sudo passenger-status"
 end
end

I think for my next Ruby on Rails post I’ll show a capistrano recipe for generating a custom maintenance.html page.