Typo on Heroku

Posted by Huy Dinh Fri, 22 Jul 2011 21:31:00 GMT

Jul 22

Using some on-line resources (for links see below), I managed to deploy bleeding edge Typo on Heroku. Despite having a virtual root server to run Typo on, I decided to have it run somewhere else, because of the limitations on my virtual root server. Namely the number of open files, for Typo wouldn't have been the only thing running on it.

Preparations

Getting Typo is not exactly difficult. All you need is git and it's just

$ git clone git://github.com/fdv/typo.git
$ cd typo

to download the most recent version of Typo into a directory typo and jumping right into that directory. And since we are working with Heroku, installing the Heroku gem provides a useful command-line interface to your Heroku app:

$ gem install heroku

Setting up the repository for Heroku

Before you can do a git push to Heroku, you need to do a few things first. They all deal with the fact that the Heroku file system is read-only by creating empty folders (and keeping them in git) and disabling write access wherever needed.

Empty folders

Empty folders first. As git ignores empty folders, we need empty files within those (then not-so-empty) folders get them into git.

$ mkdir -p public/files tmp/cache
$ touch public/files/.gitkeep tmp/cache/.gitkeep
$ git add -f public/files/.gitkeep tmp/cache/.gitkeep
$ git commit -m "Adding empty directories for Heroku."

Removing write access

Now we need to disable write access in whatever might be writing to the file system. Create a file config/preinitializer.rb containing

require 'fileutils'

file_utils_no_write = FileUtils::NoWrite
Object.send :remove_const, :FileUtils
FileUtils = file_utils_no_write

to disable copying assets from the plugins to the public folder. This seems safe to do, because Typo comes with those files in the right place already.

I haven't tried using default themes, but using my own one, I've run into HTTP 500 errors when trying to get files like /images/theme/foobar.jpg. This presumably happens because caching fails (due to read-only restrictions), so I disabled this behaviour in config/environments/production.rb:

--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -7,7 +7,7 @@ TypoBlog::Application.configure do
 
   # Full error reports are disabled and caching is turned on
   config.consider_all_requests_local = false
-  config.action_controller.perform_caching             = true
+  config.action_controller.perform_caching             = false
 
   # See everything in the log (default is :info)
   # config.log_level = :debug

This works for me, but it seems to slow down the site by quite a bit. So maybe try and store images, stylesheets, and JavaScript files somewhere else and link to them.

Lastly, the CKeditor tries to write stuff to public/javascripts. Fortunately, StackOverflow is a good friend and knows a few solutions to that problem. I went with this editing vendor/plugins/easy-ckeditor/init.rb:

--- a/vendor/plugins/easy-ckeditor/init.rb
+++ b/vendor/plugins/easy-ckeditor/init.rb
@@ -1,9 +1,9 @@
 # Include hook code here
 require 'ckeditor'
 require 'ckeditor_version'
-require 'ckeditor_file_utils'
+# require 'ckeditor_file_utils'
 
-CkeditorFileUtils.check_and_install
+# CkeditorFileUtils.check_and_install
 
 # make plugin controller available to app
 config.autoload_paths += %W(#{Ckeditor::PLUGIN_CONTROLLER_PATH} #{Ckeditor::PLUGIN_HELPER_PATH})

As pointed out on StackOverflow, a pretty ghetto-ish solution...

$ git add config/preinitializer.rb config/environments/production.rb vendor/plugins/easy-ckeditor/init.rb
$ git commit -m "Disabling write access where needed for Heroku."

Databases and gems

The easiest way to let Heroku know which gems to install probably is providing a Gemfile.lock file. Doing this instead of creating a .gems file manually will ensure that all required gems are being listed, which may be relevant if the Typo team decides to add a gem for some new feature (or just use more recent versions of some gems).

Before we can get a Gemfile.lock file, we need to set up the config/database.yml file containing this:

development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

production:
  adapter: sqlite3
  database: db/production.sqlite3
  pool: 5
  timeout: 5000

With config/database.yml in its place, we finally can fire bundle to get the Gemfile.lock we need.

$ bundle
$ git add -f Gemfile.lock config/database.yml
$ git commit -m "Adding Gemfile.lock and database.yml for Heroku"

If bundle fails for you, install the bundler gem first:

$ gem install bundler

This step is a major detour from what I have found on this topic. Chances are I'm doing too much here by implying the need of sqlite3 or so. But I think this is the more robust way to provide information about which gems we need to Heroku.

reCaptcha

For a while now (I don't know since when, as I had patched Typo for reCaptcha support some time ago), the master branch of Typo also supports reCaptcha. In order to use it, you need to enable it in the administration interface and have your reCaptcha keys, which you can get on the reCaptcha website, stored in config/initializers/recaptcha.rb.

$ git add config/initializers/recaptcha.rb
$ git commit -m "Adding reCaptcha keys."

Ship it to Heroku!

Since deploying to Heroku is as easy as a git push, that's all there is.

$ git push <your-heroku-git-reposiory> master:master

The last step to your Heroku-hosted Typo blog then is setting up the database.

$ heroku rake db:migrate

Congratulations on your own Typo blog on Heroku!

Custom Heroku domains with lighttpd

If you want your Heroku application to be reachable at http://yourdomain.com, there are a few possibilities. Heroku suggests setting the A record of your domain or subdomain to Heroku IP addresses. This may or may not be a viable option to you, but it was not one to me.

Fortunately, I found another way that did not require me to mess with the A record of my domains: Using a lighttpd reverse proxy to forward HTTP requests to Heroku:

$HTTP["host"] =~ "^(huydinh|informagics)\.eu$" {
  proxy.server  = ( "" =>
    (
      ( "host" => "75.101.163.44" ),
      ( "host" => "75.101.145.87" ),
      ( "host" => "174.129.212.2" ),
    ),
  )
}

This only sends HTTP(S) requests to my domains to the Heroku servers, while leaving all other requests untouched. A way more preferable solution to me.

To do...

As I had mentioned before, you maybe want your stylesheet/image/JavaScript files to be served statically instead of having Typo deal with /images/theme/* types of files. If you have a lighttpd (or any other web server) available anyway, it might as well offer such static files. I haven't implemented it yet, but chances are I will do so soon enough. Depending on what NewRelic and friends tell me.

Posted in , ,  | 1 comment | no trackbacks