Integrating Wordpress and Rails

When you have a good hammer everything looks like a nail. And arguably, that's the main problem with the positioning of Rails - it's often seen as a solution to everything, which is of course not true. But this is easier said than done, just a little while ago I found myself doing a dinner napkin sketch of a blog controller with trackback, ping, and comment modules. And you know what, it looked good on paper! However, I wasn't building the 'typo/wordpress/typepad' killer, the blog controller was an add-on for a Rails project, and that's when it hit me: why Rails?

My project wasn't about building a better blogging tool, hence my time would be better spent on features that really matter to my users. Furthermore, I couldn't possibly cover the same feature set as Wordpress or Typepad in the little time that I had. Hence, a new napkin appeared on the table, this time with a single word: wordpress, which also happens to be my favorite publishing platform.

Local vs Remote Wordpress installations

After a little fiddling with apache configuration files, I had my blog up and running in a grand total of less than five minutes, a solid return on investment. There are two scenarios that I considered: a locally hosted wordpress, powered by php and local apache, or, a remote installation of wordpress proxied by the local server. Both approaches have their strong and weak points: local installations are easy, but put more stress on the server. Remote installations allow for role and service separation, but come with latency overhead. In other words, pick your poison.

Local Wordpress installation

If you want to run a local copy of wordpress, and your apache is compiled with mod_php, the installation process can be as easy as creating and unzipping the wordpress files into a new directory within your rails 'public' folder. Once that is done, we need to coax apache into recognizing the difference between Rails and PHP requests:

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

# Let apache handle the PHP files - all requests that get past this rule
# are routed to the mongrel cluster (aka Rails)
#  - wordpress installation assumeed to be in 'public/wordpress'
#  - Options: NC - case insensitive
#  -          QSA - query string append
#  -          L - last rule, aka stop here if rewriterule condition is matched
RewriteRule ^/blog/?(.*)$ %{DOCUMENT_ROOT}/wordpress/$1 [NC,QSA,L]

# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

You can download the full configuration file in an archive below, but the important rule is the one right above the mongrel cluster redirect. There we are telling apache to match any request that asks for '/blog/...', reroute it to 'public/wordpress', and evaluate the request instead of passing it to the mongrel cluster. As long as you have apache with php support compiled (or as a module), that's all you will need!

Remote Wordpress installations

In the end I chose to use a remote wordpress installation just to keep things tidy in my Rails root. I installed wordpress on a different server and added the following rules to my apache config:

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

# Let apache handle the PHP files - all requests that get past this rule
# are routed to the mongrel cluster (aka Rails)
#  - wordpress installation assumeed to be in 'public/wordpress'
#  - Options: P - proxy request
#  -          NC - case insensitive
#  -          QSA - query string append
#  -          L - last rule, aka stop here if rewriterule condition is matched
RewriteRule ^/blog/?(.*)$ http://xxx.xxx.xxx.xx/~user/blog/$1 [P,NC,QSA,L]

# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

The configuration is almost identical, except this time we have a new mod_rewrite directive: P, which stands for proxy. We redirect the request to another server, and tell apache to perform this on our behalf. The process is transparent to the user, it is as if the php server is located on the local machine. However, a warning is due, be careful of latency! You now have an extra point of failure.

apache-configs.zip - Full Apache vhost configs

As an added bonus, we can also move our new mod_rewrite rule before the maintenance file check for capistrano. This way, if you disable your application, your blog will still be active, allowing you to keep in touch with your users and keep the best of both worlds - the flexibility of your favorite publishing platform, and the fun of developing you core product in Rails.


Ilya Grigorik

Ilya Grigorik is a web performance engineer and developer advocate at Google, where his focus is on making the web fast and driving adoption of performance best practices at Google and beyond.