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.