Rails Virtual Hosts With mod_macro

15 Oct 2009

I’m using Apache with Passenger to serve web sites. Initially I was keeping each Rails virtual host in separate files, but then the number of site’s increased I saw a problem. I’m a coder and when I see copy & paste duplication I know this is wrong.

I needed to reuse my configurations, a templating system would be nice. I’ve found that mod_macro module can accomplish this task.

To install the mod_macro module, download the right tarball which matches your Apache version:

Ensure that the httpd-devel package is installed and then extract the archive and compile and load the mod_macro module with apxs tool:

# wget http://www.cri.ensmp.fr/~coelho/mod_macro/mod_macro-1.1.10.tar.bz2
# tar xvfjp mod_macro-1.1.10.tar.bz2
# cd mod_macro-1.1.10
# apxs -cia mod_macro.c

I’m keeping my macros (templates) in a configuration file under Apache’s conf.d directory. I’ve created a new macro for Ruby on Rails called RailsHost $host $dir which accepts two paramters (host and app root). Example usage:

# /etc/httpd/conf/httpd.conf
[...]
Use RailsHost vhost1.com /var/www/vhosts/vhost1.com
Use RailsHost vhost2.com /var/www/vhosts/vhost2.com

Now, it’s much easier to add new virtual hosts, it requires a single line for each virtual host and my Apache configuration looks much better.

# /etc/httpd/conf.d/macros.conf

# RailsHost macro
<Macro RailsHost $host $dir>
  <VirtualHost *:80>
    ServerName www.$host
    ServerAlias $host
    DocumentRoot $dir/current/public

    CustomLog "logs/$host_access.log" combined
    ErrorLog "logs/$host_error.log"

    # Passenger settings
    RailsBaseURI /
    RailsMaxPoolSize 1
    RailsPoolIdleTime 3600
    RailsEnv production

    # Redirect example.com -> www.example.com
    RewriteEngine On
    RewriteCond %{HTTP_HOST} !^www.$host
    RewriteRule ^/(.*) http://www.$host/$1 [R=301,L]

    # Check for maintenance file and redirect all requests
    RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
    RewriteCond %{SCRIPT_FILENAME} !maintenance.html
    RewriteCond %{SCRIPT_FILENAME} !^/images
    RewriteCond %{SCRIPT_FILENAME} !^/stylesheets
    RewriteCond %{SCRIPT_FILENAME} !^/javascripts
    RewriteRule ^.*$ /system/maintenance.html [L]

    ErrorDocument 404 $dir/current/public/404.html
    ErrorDocument 422 $dir/current/public/422.html
    ErrorDocument 500 $dir/current/public/500.html

    Use ModDeflate
    Use ModExpires

    <Directory $dir/current/public>
      Options FollowSymLinks
      AllowOverride None
      Order allow,deny
      Allow from all
    </Directory>
  </VirtualHost>
</Macro>

# ModDeflate macro
<Macro ModDeflate>
  <IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript

    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  </IfModule>
</Macro>

# ModExpires macro
<Macro ModExpires>
  <IfModule mod_expires.c>
    ExpiresActive On
    <LocationMatch "^/(images|javascripts|stylesheets)">
      ExpiresDefault "access plus 1 year"
    </LocationMatch>
  </IfModule>
</Macro>