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

Back on Typo 6.0.3 and Rails 3.0!

Posted by Huy Dinh Tue, 15 Feb 2011 01:32:00 GMT

Feb 15

When I found out the hard way that mongrel's daemonized mode doesn't really work with Rails 3, I had to find some other feasible way to deploy Rails applications. I did end up trying mod_rails and Apache 2.2, but its process-based nature wasn't working well on the virtual server it was supposed to run on, because of the restricted number of processes at the same time. Since there are other services running on the virtual server, this setup ended up getting very close to the limit. Which obviously is bad.

So there was my excuse to just keep lighttpd running. The more difficult part now was to find a way to actually run Rails. I ended up sticking with Thin. Both lighttpd and Thin are horribly easy to set up on a user without root privileges. (Getting the Debian package of Apache 2.2 to run on non-root takes quite some time, compared to this.)

The easiest way to install Thin probably is gem install thin. Depending on the operating system you are using, installing lighttpd can be either a plain aptitude install lighttpd or some more tedious compiling.

#!/bin/sh

case "$1" in
    devel.huydinh.eu)
        THINPROJECT=devel.huydinh.eu
        THINPORT=3000
        THINENV=development
        ;;
    huydinh.eu)
        THINPROJECT=huydinh.eu
        THINPORT=8081
        THINENV=production
        ;;
    *)
        echo "Please choose an existing project."
        exit 2
        ;;
esac

THINDIR=$HOME/doc/$THINPROJECT
THINPID=$HOME/var/run/thin.$THINPORT.pid
THINLOG=$HOME/var/log/thin/$THINPROJECT.log

DAEMON="$HOME/lib/ruby/gems/1.8/bin/thin"
DAEMON_ARGS="-a 127.0.0.1 -p $THINPORT -c $THINDIR -e $THINENV -d -l $THINLOG -P $THINPID --tag $THINPROJECT"

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

case "$2" in
    start)
        $DAEMON $DAEMON_ARGS $2 && echo "Thin started and daemonized."
        ;;
    force-reload|status|stop)
        $DAEMON $DAEMON_ARGS $2
        ;;
    restart)
        $0 $1 stop
        $0 $1 start
        ;;
    *)
        echo "Usage: thinctl PROJECT {start|stop|status|restart|force-reload}" >&2
        exit 3
        ;;
esac

This wraps starting and stopping Thin instances (I should rewrite this to use configuration files for Thin) and all there is left to do is to set up lighttpd as a reverse HTTP proxy. Which is about just as easy:

$HTTP["host"] =~ "^devel\.huydinh\.eu$" {
    proxy.server = ( "" =>
        (
            ( "host" => "127.0.0.1", "port" => "3000" ),
        ),
    )
}

$HTTP["host"] =~ "^www\.huydinh\.eu$" {
    url.redirect = (
        "^/(.*)" => "https://huydinh.eu/$1"
    )
}

$HTTP["host"] =~ "^huydinh\.eu$" {
    proxy.server  = ( "" =>
        (
            ( "host" => "127.0.0.1", "port" => "8081" ),
        ),
    )
}

There is some lighttpd spell that would let lighttpd handle static files in /javascripts, /images etc., but it seems to break Typo. That's why it's not included.

Setting up both lighttpd and Thin from scratch probably took me less time than getting Apache 2.2 run on the non-root user. That's before setting up mod_rails...

I wasn't all too certain about this setup when running in development mode (on devel.huydinh.eu), because it felt pretty slow, even for RAILS_ENV=development. The second I tested the production version however, I was happy.

So after a looong time: Typo 6.x and Rails 3.x!

As for the old content, I do not really intend to bring them back as a whole. But I think I will revamp some of the more interesting posts and put them back up here as time permits.

Posted in  | Tags , , , , , , , ,  | no comments | no trackbacks