<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[shapeshed]]></title>
  
  <link href="http://shapeshed.com//" />
  <updated>2012-01-04T10:11:25+00:00</updated>
  <id>http://shapeshed.com//</id>
  <author>
    <name><![CDATA[George Ornbo]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/shapeshed" /><feedburner:info uri="shapeshed" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by/3.0/" /><xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" /><feedburner:emailServiceId>shapeshed</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><entry>
    <title type="html"><![CDATA[Compiling Node.js from source on Ubuntu 10.04]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/PjWLgJUawD8/" />
    <updated>2012-01-04T00:00:00+00:00</updated>
    <id>http://shapeshed.com//compiling-nodejs-from-source-on-ubuntu-10-04</id>
    <content type="html">&lt;p&gt;Compiling Node.js from source is easy enough so here&amp;#8217;s how.&lt;/p&gt;

&lt;h2&gt;Installing from a tarball&lt;/h2&gt;

&lt;p&gt;Node.js needs a few things to compile so make sure they are installed.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Installing Node.js dependencies&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo apt-get update
&lt;/span&gt;&lt;span class='line'&gt;sudo apt-get install build-essential openssl libssl-dev pkg-config
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Get the link for the latest tarball from the Source Code link on the &lt;a href="http://nodejs.org/#download"&gt;Node.js homepage&lt;/a&gt;. Then download it and extract it.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Downloading and extracting the tarball&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/src
&lt;/span&gt;&lt;span class='line'&gt;sudo mkdir node
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;node
&lt;/span&gt;&lt;span class='line'&gt;sudo wget http://nodejs.org/dist/v0.6.6/node-v0.6.6.tar.gz
&lt;/span&gt;&lt;span class='line'&gt;sudo tar -xzf node-v0.6.6.tar.gz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now you can compile and install the binary. By default Node.js will be installed to &lt;code&gt;/usr/local/bin/node&lt;/code&gt; and npm will be installed to &lt;code&gt;/usr/local/bin/npm&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Compiling Node.js&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;node-v0.6.6/
&lt;/span&gt;&lt;span class='line'&gt;sudo ./configure
&lt;/span&gt;&lt;span class='line'&gt;sudo make
&lt;/span&gt;&lt;span class='line'&gt;sudo make install
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Upgrading via a tarball&lt;/h2&gt;

&lt;p&gt;To upgrade Node.js simply download the new tarball, extract and repeat the installation process.&lt;/p&gt;

&lt;h2&gt;Installing from Git&lt;/h2&gt;

&lt;p&gt;If you plan to upgrade each time a new release comes out you may find cloning the Git repository more convenient than downloading and extracting  a tarball each time.&lt;/p&gt;

&lt;p&gt;You will need Git and the dependencies to be installed first.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Installing Node.js dependencies&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo apt-get update
&lt;/span&gt;&lt;span class='line'&gt;sudo apt-get install git-core build-essential openssl libssl-dev pkg-config
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Using Git means that instead of downloading extracting a tarball you can just clone the repository and checkout the latest version. If you need to check the versions that are available run &lt;code&gt;git tag&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Cloning the Node.js Git repository&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/src
&lt;/span&gt;&lt;span class='line'&gt;sudo git clone git://github.com/joyent/node.git
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;node
&lt;/span&gt;&lt;span class='line'&gt;sudo git checkout v0.6.6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now you can compile the binary as before&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Compiling Node.js&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo ./configure
&lt;/span&gt;&lt;span class='line'&gt;sudo make
&lt;/span&gt;&lt;span class='line'&gt;sudo make install
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Upgrading via Git&lt;/h2&gt;

&lt;p&gt;To upgrade to a new release of Node.js first pull the latest source.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Pulling the latest Node.js source &lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/src/node
&lt;/span&gt;&lt;span class='line'&gt;sudo git checkout master
&lt;/span&gt;&lt;span class='line'&gt;sudo git pull origin master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then checkout the latest version where &lt;code&gt;v.x.x.x&lt;/code&gt; is the version you want.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Checking out the latest version&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo git checkout vx.x.x
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then follow the installation process as before&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Compiling Node.js&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo ./configure
&lt;/span&gt;&lt;span class='line'&gt;sudo make
&lt;/span&gt;&lt;span class='line'&gt;sudo make install
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This will upgrade Node.js and overwrite the previous version.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/PjWLgJUawD8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//compiling-nodejs-from-source-on-ubuntu-10-04/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Using rbenv to manage rubies]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/vy7DUL8uksM/" />
    <updated>2011-10-12T00:00:00+01:00</updated>
    <id>http://shapeshed.com//using-rbenv-to-manage-rubies</id>
    <content type="html">&lt;h2&gt;rbenv is great&lt;/h2&gt;

&lt;p&gt;If you haven&amp;#8217;t seen &lt;a href="https://github.com/sstephenson/rbenv"&gt;rbenv&lt;/a&gt; yet I highly recommend it. It is a small collection of shell scripts that lets you manage rubies on UNIX type machines. To date I&amp;#8217;ve used &lt;a href="http://beginrescueend.com/"&gt;rvm&lt;/a&gt; to install versions of ruby and manage gemsets. Don&amp;#8217;t get me wrong - I&amp;#8217;m hugely greatful to the work that has gone into the rvm project and it is still a great tool. But I prefer the UNIX philosophy of doing one thing well and rbenv embraces that. I also really like that with rbenv you just need to amend your PATH and you are done. It follows UNIX conventions making integration with other UNIX tools easier - for me at least.&lt;/p&gt;

&lt;h2&gt;rbenv basics&lt;/h2&gt;

&lt;p&gt;We have a dev machine at work which runs a variety of Sinatra and Rails projects (including a Rails 1 project). As such these projects need lots of different versions of Ruby. To date I&amp;#8217;ve used rvm to manage this and it has worked well but I always came up against issues when trying to integrate tools like Monit, puppet or init.d scripts. So I bit the bullet and switched to rbenv.&lt;/p&gt;

&lt;p&gt;Each app has a UNIX user so rbenv is installed locally for each user when logged in as the user account&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Cloning rbenv&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;git clone git://github.com/sstephenson/rbenv.git .rbenv
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You need to load rbenv into the shell and you are good to go&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Adding rbenv to your PATH&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;export PATH=&amp;quot;$HOME/.rbenv/bin:$PATH&amp;quot;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;eval &amp;quot;$(rbenv init -)&amp;quot;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you have installed &lt;a href="https://github.com/sstephenson/ruby-build"&gt;ruby-build&lt;/a&gt; you can then install rubies with &lt;code&gt;rbenv install&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Installing a ruby&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rbenv install 1.9.3-rc1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You can set a global ruby for the user account with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Setting a global ruby&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rbenv global 1.9.3-rc1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And you can also use an &lt;code&gt;.rbenv-version&lt;/code&gt; file to set the version. I choose to use this in projects and check it into git.&lt;/p&gt;

&lt;h2&gt;Deployment with capistrano&lt;/h2&gt;

&lt;p&gt;I like that rbenv doesn&amp;#8217;t try and manage rubies for you - we have &lt;a href="http://gembundler.com/"&gt;bundler&lt;/a&gt; for that. I deploy as the same user as the app accounts so I just need to add the following to my cap recipe to use rbenv since I&amp;#8217;m already including &lt;code&gt;require 'bundler/capistrano'&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Adding the PATH to Capistrano&amp;#8217;s Shell&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:default_environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="s1"&gt;&amp;#39;PATH&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/youruser/.rbenv/shims:/home/youruser/.rbenv/bin:$PATH&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This loads rbenv into the shell that capistrano uses. That&amp;#8217;s pretty much all you need to use your rbenv installed ruby.&lt;/p&gt;

&lt;p&gt;Following a &lt;a href="https://github.com/sstephenson/rbenv/issues/101"&gt;thread on github&lt;/a&gt; you can also apply a clever technique to allow you switch versions of ruby by pushing a new &lt;code&gt;.rbenv-version&lt;/code&gt; file with capistrano. From version 1.1rc bundler allows you to specify a shebang for binstubs. To use this add the following to your capistrano recipe.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Adding binstubs for easy ruby switching&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="ss"&gt;:bundle_flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--deployment --quiet --binstubs --shebang ruby-local-exec&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This generates executables in the bin folder of your Rails app which reference &lt;code&gt;ruby-local-exec&lt;/code&gt; as the shebang. This command will execute whichever ruby is specified in the &lt;code&gt;.rbenv-version file&lt;/code&gt;. In my case I have an init.d script to manage unicorn that references bin/unicorn. If I wanted to upgrade the ruby used by the app I would install it on the remote machine and then just update my &lt;code&gt;.rbenv-version&lt;/code&gt; file commit, cap deploy and I&amp;#8217;m done.&lt;/p&gt;

&lt;h2&gt;Integrating with other tools&lt;/h2&gt;

&lt;p&gt;I like to use &lt;a href="http://mmonit.com/monit/"&gt;monit&lt;/a&gt; to monitor processes. Monit exexutes scripts with a very limited shell but since rbenv follows UNIX conventions we can easily create a small bash script to load rbenv into the path and then do what we want.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the script I&amp;#8217;m using for starting a resque_worker&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;resque_worker bash script&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;youruser
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;APP_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/srv/yourapp.com/current
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/&lt;span class="nv"&gt;$USER&lt;/span&gt;/.rbenv/bin:/home/&lt;span class="nv"&gt;$USER&lt;/span&gt;/.rbenv/shims:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$RAILS_ENV&lt;/span&gt; bin/rake environment resque:work&amp;amp; &amp;gt; &lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;/log/resque_worker.log
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$!&lt;/span&gt; &amp;gt; &lt;span class="nv"&gt;$APP_PATH&lt;/span&gt;/tmp/pids/resque_worker.pid
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then my monit task looks like this&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;resque_worker monit script&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;check process yourapp_resque_worker
&lt;/span&gt;&lt;span class='line'&gt;    with pidfile /srv/yourapp.com/current/tmp/pids/resque_worker.pid
&lt;/span&gt;&lt;span class='line'&gt;    start &lt;span class="nv"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/bin/sh -c &amp;#39;/home/youruser/bin/start_resque_worker.sh&amp;#39;&amp;quot;&lt;/span&gt; as uid youruser and gid youruser
&lt;/span&gt;&lt;span class='line'&gt;    stop &lt;span class="nv"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/bin/sh -c &amp;#39;cd /srv/yourapp.com/current &amp;amp;&amp;amp; kill -s quit `cat tmp/pids/resque_worker.pid` &amp;amp;&amp;amp; rm -f tmp/pids/resque_worker.pid; exit 0;&amp;#39;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Better separation&lt;/h2&gt;

&lt;p&gt;By using rbenv, bundler, capistrano and monit together we have great separation between what these tools do&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rbenv manages rubies&lt;/li&gt;
&lt;li&gt;bundler manages gems&lt;/li&gt;
&lt;li&gt;capistrano manages deployments&lt;/li&gt;
&lt;li&gt;monit monitors processes&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This feels clean and manageable to me.&lt;/p&gt;

&lt;p&gt;By using binstubs with the &lt;code&gt;ruby-local-exec&lt;/code&gt; shebang we also separate our app from versions of rubies, init.d and monit scripts, making it super easy to upgrade.&lt;/p&gt;

&lt;h2&gt;Thanks rvm, onwards with rbenv&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m really grateful to Wayne E Seguin and the work he has put into rvm and I hope the project continues to thrive. rbenv fits the way I work though and I&amp;#8217;m really enjoying using it. It makes piecing tools like puppet, monit, init.d scripts, capistrano and bundler much easier, so a big thanks to &lt;a href="http://sstephenson.us/"&gt;Sam Stephenson&lt;/a&gt; for creating it.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/vy7DUL8uksM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//using-rbenv-to-manage-rubies/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Managing Unicorn Workers with Monit]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/6WgSjmNCOt0/" />
    <updated>2011-09-12T00:00:00+01:00</updated>
    <id>http://shapeshed.com//managing-unicorn-workers-with-monit</id>
    <content type="html">&lt;h2&gt;Riding Unicorns&lt;/h2&gt;

&lt;p&gt;For many reasons I like using &lt;a href="http://unicorn.bogomips.org/"&gt;Unicorn&lt;/a&gt; as a web server for Ruby apps. &lt;a href="http://tomayko.com/"&gt;Ryan Tomayko&lt;/a&gt; wrote a &lt;a href="http://tomayko.com/writings/unicorn-is-unix"&gt;great article&lt;/a&gt; and the many Unix features that it has. It has the killer feature of supporting hot restarts so you can deploy new releases with zero downtime. This means that in most cases you can deploy as often as you want and end users won&amp;#8217;t even notice.&lt;/p&gt;

&lt;h2&gt;More power == more responsibility&lt;/h2&gt;

&lt;p&gt;With all of the great stuff that comes with Unicorn there is more configuration to do. This is the point at which the less intrepid opt for &lt;a href="http://www.modrails.com/"&gt;Passenger&lt;/a&gt;, that to be fair is stil a good option. But if you want a web server that uses great features of Unix and enables hot restarts you should persevere.&lt;/p&gt;

&lt;p&gt;For Unicorn you need to set up a reverse proxy with nginx. I&amp;#8217;ve &lt;a href="http://shapeshed.com/journal/building-a-rails-development-server/"&gt;written before&lt;/a&gt; about how to do that if you need a steer. You&amp;#8217;ll also need to use upstart or script in /etc/init.d/ to manage Unicorn. There are a few scripts around on the web. I&amp;#8217;ve posted the one that I use up as &lt;a href="https://gist.github.com/1221753"&gt;a gist on Github&lt;/a&gt;. You can then use something like this in your capistrano recipes to do a hot restart.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Hot restarts with unicorn&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ss"&gt;:deploy&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:restart&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/etc/init.d/unicorn upgrade&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This sends a &lt;code&gt;USR2&lt;/code&gt; signal to the Unicorn master process to upgrade itself. It will create a new master process and then switch over when it is ready. See - zero downtime!&lt;/p&gt;

&lt;h2&gt;Up the workers&lt;/h2&gt;

&lt;p&gt;The Unicorn master process looks after workers and will reap workers that die from broken apps. In my scenario I was working on a memory constrained box and I wanted to make sure that workers did not consume too much memory. I like to use &lt;a href="http://mmonit.com/monit/"&gt;Monit&lt;/a&gt; to monitor processes. You can also use &lt;a href="http://god.rubyforge.org/"&gt;god&lt;/a&gt; or &lt;a href="https://github.com/arya/bluepill"&gt;bluepill&lt;/a&gt; but I&amp;#8217;ve found these tools consume much more memory that Monit. Call me old fashioned but I like to use Unix tools if they are available over Ruby.&lt;/p&gt;

&lt;p&gt;So I want to monitor the Unicorn workers that are a child processes of the master Unicorn process. Bluepill supports monitoring child processes but it turns out this is easy enough to do with Monit.&lt;/p&gt;

&lt;p&gt;Unicorn&amp;#8217;s config file has an after_fork method that allows you to write out the pid of a worker. Here&amp;#8217;s how&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Writing worker pids in Unicorn&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;after_fork&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;establish_connection&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;child_pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:pid&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.pid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.pid&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;echo &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;child_pid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you want to see my full &lt;a href="https://gist.github.com/1221753#file_unicorn.rb"&gt;unicorn.conf&lt;/a&gt; it is here. This will write out the pid of each worker &lt;code&gt;/tmp/pids/unicorn.[pid_id].pid&lt;/code&gt;, so now we can use Monit to watch it.&lt;/p&gt;

&lt;h2&gt;Adding in Monit&lt;/h2&gt;

&lt;p&gt;Now that we have the pids of workers and an init.d script that can manage workers too (see kill_worker) we can use Monit to keep everything in check. The only downside is that you need to tell Monit about each worker process that you have. If you are spawning and reaping Unicorn workers dynamically with &lt;code&gt;TTIN&lt;/code&gt; and &lt;code&gt;TTOU&lt;/code&gt; this probably isn&amp;#8217;t going to work for you. But if the numbers of workers are fixed you are good.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;A monit script to monitor unicorn workers&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;check process unicorn_worker_0
&lt;/span&gt;&lt;span class='line'&gt;    with pidfile /path/to/your/app/shared/pids/unicorn.0.pid
&lt;/span&gt;&lt;span class='line'&gt;    start &lt;span class="nv"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/bin/cat /dev/null&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    stop &lt;span class="nv"&gt;program&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/etc/init.d/unicorn kill_worker 0&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;if &lt;/span&gt;mem is greater than 175.0 MB &lt;span class="k"&gt;for &lt;/span&gt;1 cycles &lt;span class="k"&gt;then &lt;/span&gt;restart
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;if &lt;/span&gt;cpu is greater than 22% &lt;span class="k"&gt;for &lt;/span&gt;2 cycles &lt;span class="k"&gt;then &lt;/span&gt;alert
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="k"&gt;if &lt;/span&gt;cpu is greater than 25% &lt;span class="k"&gt;for &lt;/span&gt;1 cycles &lt;span class="k"&gt;then &lt;/span&gt;restart
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Monit will watch the worker for memory growth and kill it off if it consumes too much. The unicorn master will spawn a new worker when it is killed so it is a neat solution to keep things running.&lt;/p&gt;

&lt;p&gt;Much of this article was derived from Andrew Grim&amp;#8217;s article &lt;a href="http://www.stopdropandrew.com/2010/06/01/where-unicorns-go-to-die-watching-unicorn-workers-with-monit.html"&gt;&amp;#8216;Where Unicorns go to die: Watching unicorn workers with monit&amp;#8217;&lt;/a&gt;, so thanks to Andrew for the pointers.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/6WgSjmNCOt0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//managing-unicorn-workers-with-monit/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Migrating from Slicehost to Linode]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/_ATuchk67TE/" />
    <updated>2011-08-29T00:00:00+01:00</updated>
    <id>http://shapeshed.com//migrating-from-slicehost-to-linode</id>
    <content type="html">&lt;h2&gt;Slicehost was a game changer&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve been a long standing &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; customer, after moving from &lt;a href="http://mediatemple.net/"&gt;Media Temple&lt;/a&gt;. Slicehost was perfect for my needs - I knew my way around Linux so I just wanted SSH access and the ability to configure it myself. At $20 a month Slicehost was a ground-breaking service. Coupled with a &lt;a href="http://articles.slicehost.com/"&gt;blog&lt;/a&gt; that spoke to developers about how to do things developers were doing every day it provided a range of distributions and was a massive hit with the developer community. On October 22nd 2008 Slicehost &lt;a href="http://www.slicehost.com/articles/2008/10/22/big-news-today"&gt;announced&lt;/a&gt; that they had been acquired by &lt;a href="http://www.rackspace.com/"&gt;Rackspace&lt;/a&gt;. This was a just reward for what Slicehost had achieved  but immediately there were concerns as to the direction of the service.&lt;/p&gt;

&lt;p&gt;From public accounts Rackspace has used Slicehost&amp;#8217;s underlying technology to build their &lt;a href="http://www.rackspace.com/cloud/"&gt;Rackspace Cloud&lt;/a&gt;. In May 2011 Rackspace contacted &lt;a href="http://thenextweb.com/dd/2011/05/03/rackspace-to-shut-down-slicehost/"&gt;Slicehost customers&lt;/a&gt; to say they would be migrated to the Rackspace Cloud product.&lt;/p&gt;

&lt;h2&gt;PR Car Crash&lt;/h2&gt;

&lt;p&gt;The email to customers raised more questions that it gave answers causing many customers to leave Slicehost there and then. There were so many questions that a further post was &lt;a href="http://forum.slicehost.com/comments.php?DiscussionID=5210"&gt;added to the forum&lt;/a&gt; which in fairness addressed many of the questions that customers had. At that point it became clear that the service Rackspace were offering was very different from Slicehost:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS moving to Rackspace&amp;#8217;s service. Unknown if it would be free&lt;/li&gt;
&lt;li&gt;Lower bandwidth allowance with pricing moving to pay what you use&lt;/li&gt;
&lt;li&gt;Some servers moving datacenters and changing IP addresses&lt;/li&gt;
&lt;li&gt;Removal of some Slice sizes&lt;/li&gt;
&lt;li&gt;Slicehost API likely to close&lt;/li&gt;
&lt;li&gt;A requirement to migrate to Rackspace by May 2012&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Particularly if you use more than 60GB of bandwidth a month the service Rackspace&amp;#8217;s Cloud Service would be more expensive.&lt;/p&gt;

&lt;h2&gt;Free markets are good&lt;/h2&gt;

&lt;p&gt;Thankfully the hosting market is very competitive and even Slicehost has competition in the form of &lt;a href="http://www.linode.com/"&gt;Linode&lt;/a&gt;, a service launched in 2003. Linode offer a very similar service to Slicehost with the ability to provision servers, get SSH access and build it yourself. In fact Linode&amp;#8217;s offering to customers is more competitive than Slicehost with 512MB of RAM offered for the entry price of $20 a month. Linode also offer free DNS servers, a great API and has also been a strong hit with the developer coummunity.&lt;/p&gt;

&lt;p&gt;After looking at the direction of Rackspace Cloud and what Linode offer for the same price the clear choice was to migrate to the better product: Linode.&lt;/p&gt;

&lt;h2&gt;The pain of migrating&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ve been with Slicehost for a while so with that comes many configurations, DNS zones and a server setup exactly how I like it. Rebuilding servers is tedious and sadly I built mine before &lt;a href="http://www.puppetlabs.com/"&gt;Puppet&lt;/a&gt; was around. I use Puppet at work and this has shown me there is huge value in automating server management, especially in the context of Cloud providers.&lt;/p&gt;

&lt;p&gt;After the decision to migrate I was staring at a terminal with many hours of work ahead of me, until the power of open source came to the rescue.&lt;/p&gt;

&lt;h2&gt;Migrating DNS&lt;/h2&gt;

&lt;p&gt;Firstly for migrating DNS records Rob Schultz created a short &lt;a href="https://github.com/Schultz/slicedns2linode"&gt;Ruby script&lt;/a&gt; to migrate DNS records from Slicehost to Linode. Once you&amp;#8217;ve installed the script and necessary gem dependencies migrating your records is as simple at&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;./slicedns2linode.rb domain1.com.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Within a few minutes I had migrated all of my DNS records.&lt;/p&gt;

&lt;h2&gt;Migrating the server&lt;/h2&gt;

&lt;p&gt;If you are not already using Chef or Puppet there is a project called &lt;a href="https://github.com/devstructure/blueprint"&gt;Blueprint&lt;/a&gt; that lets your reverse engineer a server configuration to a bash script, Puppet manifests or Chef cookbook. There is a &lt;a href="https://devstructure.com/docs/tutorial.html"&gt;good tutorial&lt;/a&gt; on a basic migration. Once you&amp;#8217;ve installed blueprint and the dependencies you can create a shell script that will build another server with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;blueprint create -S tutorial&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Once you&amp;#8217;ve created your scripts, just run them on the target server and it will build the server in the image of the old one.&lt;/p&gt;

&lt;h2&gt;My experience of Blueprint&lt;/h2&gt;

&lt;p&gt;The migration via blueprint went very smoothly. I had installed lots of packages adding third party repositories and compiling from source. Other than &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;gitosis&lt;/a&gt; packages were mostly copied over and iptables was successfully configured.&lt;/p&gt;

&lt;h2&gt;Finishing up with scp&lt;/h2&gt;

&lt;p&gt;Finally I had to copy over website, home folder files and a few config files. The perfect tool for this was scp. First I created a tar.bz2 archive for folders I wanted to copy.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;tar -cjf vhosts.tar.bz2 /var/www/vhosts&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then I copied over the archive to my new Linode instance&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;scp vhosts.tar.bz2 george@123.456.78.90:/var/www&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Finally I unarchived it on the Linode instance&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;tar -xjf vhosts.tar.bz2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The great thing about using this approach is that permissions are preserved.&lt;/p&gt;

&lt;p&gt;The last part was to change the name servers for my domains over to Linode.&lt;/p&gt;

&lt;h2&gt;Thanks Slicehost&lt;/h2&gt;

&lt;p&gt;Slicehost was a great service and the articles in particular helped me to skill up on UNIX and respond to many different scenarios. I&amp;#8217;m sad that Slicehost will no longer be around and in particular that the service offering is so different from Rackspace. Slicehost was cloud hosting before it became trendy and now cloud hosting is something entirely different. I hope Linode can make me as happy - so far so good.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/_ATuchk67TE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//migrating-from-slicehost-to-linode/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Going realtime with node.js, Express and socket.io]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/qJ7MkfpGBOA/" />
    <updated>2011-07-18T00:00:00+01:00</updated>
    <id>http://shapeshed.com//going-realtime-with-nodejs-express-and-socket-io</id>
    <content type="html">&lt;h2&gt;Counting is fun!&lt;/h2&gt;

&lt;p&gt;This is a walkthrough on how to create a simple realtime counter of visitors to a page using &lt;a href="http://nodejs.org"&gt;node.js&lt;/a&gt;, &lt;a href="http://socket.io/"&gt;socket.io&lt;/a&gt; and &lt;a href="http://expressjs.com/"&gt;express&lt;/a&gt;. This example is very simple but could easily be extended to a range of applications.&lt;/p&gt;

&lt;h2&gt;Just show me the app&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://counter.nodester.com"&gt;&lt;img src="http://shapeshed.com/images/articles/counter.jpg" alt="Simple counter" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://counter.nodester.com"&gt;http://counter.nodester.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Pulling the pieces together&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://expressjs.com/"&gt;Express&lt;/a&gt; is a great web framework for creating sites in node.js. I&amp;#8217;ve &lt;a href="http://shapeshed.com/journal/creating-a-basic-site-with-node-and-express/"&gt;written before&lt;/a&gt; about creating a basic site. This time we are going to use a couple more libraries to add realtime communication to the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://socket.io/"&gt;socket.io&lt;/a&gt; is an amazing library that takes the pain out of websockets and provides a reliable fallback depending on browser capabilites. Here&amp;#8217;s a simple example from the socket.io site.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Setting up socket.io on the server side&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;socket.io&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;connection&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;news&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my other event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This sets up the server side. Then you just need to add some client-side JavaScript and you are ready to go&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Setting up socket.io on the client side&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/socket.io/socket.io.js&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://localhost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;news&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;my other event&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;data&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;/script&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I&amp;#8217;ve used this setup to push the number of connected clients out to the browser and a simple counter to increment and decrement the number of connected clients on the relevant events. I&amp;#8217;ve had some issues with different browsers on hosting environments. For now the demo works with Safari and Chrome.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://smoothiecharts.org/"&gt;Smoothie Charts&lt;/a&gt; is a great library that will draw graphs in JavaScript. It is very customisable, and lightweight and is specifically designed for live, streaming data. It uses canvas to draw the graphs and the &lt;a href="http://smoothiecharts.org/tutorial.html"&gt;tutorial&lt;/a&gt; shows just how easy it is to create a realtime charts.&lt;/p&gt;

&lt;p&gt;Bringing these libraries together gives us live, realtime graphs. There&amp;#8217;s no persistence here but if we wanted to we could add something like &lt;a href="http://redis.io/"&gt;Redis&lt;/a&gt; into the mix to persist the maximum number of connections.&lt;/p&gt;

&lt;p&gt;You can browse the source and see how the libraries are used on &lt;a href="https://github.com/shapeshed/counter"&gt;Github&lt;/a&gt;. Fork it!&lt;/p&gt;

&lt;h2&gt;Potentials uses&lt;/h2&gt;

&lt;p&gt;We could use this kind of setup to show realtime stats on server resources of the kind provided by &lt;a href="http://munin-monitoring.org/"&gt;Munin&lt;/a&gt;, to create realtime statistics for a page, or to stream live data from a third party API to a page. I&amp;#8217;m excited about what people are going to make with these libraries!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/qJ7MkfpGBOA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//going-realtime-with-nodejs-express-and-socket-io/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Instant Rails dev environments with Tmuxinator and Foreman]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/L-mcz1uLlbI/" />
    <updated>2011-07-06T00:00:00+01:00</updated>
    <id>http://shapeshed.com//instant-rails-dev-environments-with-tmuxinator-and-foreman</id>
    <content type="html">&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;To begin working on a Rails app I need to do things like starting a server, starting a console, ensure background processes are running, start a terminal window so I can watch logs, start a text editor etc etc.&lt;/p&gt;

&lt;p&gt;Doing all this is tedious. Wouldn&amp;#8217;t it be nice if we could just do something like?&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;start_myapp&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Well you can!&lt;/p&gt;

&lt;h2&gt;Tmux&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://tmux.sourceforge.net/"&gt;Tmux&lt;/a&gt; is a &amp;#8216;terminal multiplexer&amp;#8217;. What the hell&amp;#8217;s that? It basially allows you to create terminal sessions - similar to &lt;a href="http://www.gnu.org/software/screen/"&gt;GNU Screen&lt;/a&gt; where you can detach from a session and come back later. If you are not familiar with tmux there are a few good resources available&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://peterc.org/blog/2010/216-tmux.html"&gt;A quick tmux (terminal multiplexer) screencast (a better GNU screen)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://robots.thoughtbot.com/post/2166174647/love-hate-tmux"&gt;Love, hate, &amp;amp; tmux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.hawkhost.com/2010/06/28/tmux-the-terminal-multiplexer/"&gt;TMUX - The Terminal Multiplexer (Part 1)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.hawkhost.com/2010/07/02/tmux-%E2%80%93-the-terminal-multiplexer-part-2/"&gt;TMUX - The Terminal Multiplexer (Part 2)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;You can install tmux with homebrew&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;brew install tmux&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It takes a little reading and configuring but is well worth effort if you are a heavy terminal user.&lt;/p&gt;

&lt;h2&gt;Tmuxinator&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/aziz/tmuxinator"&gt;Tmuxinator&lt;/a&gt; is an excellent gem that lets you define the layouts of your tmux sessions.&lt;/p&gt;

&lt;p&gt;You can install tmuxinator from RubyGems&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;gem install tmuxinator&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;By defining a yaml file we can layout things exactly how we want them.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;tmuxinator project layout file&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='yaml'&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;project_name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;myapp&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;project_root&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;~/Sites/myapp&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="l-Scalar-Plain"&gt;tabs&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;zsh&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;vim&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;vim .&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;foreman&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;bundle exec foreman start&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;git&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;git pull&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;console&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;bundle exec rails console&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;server&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;bundle exec rails server&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;logs&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;tail -f log/development.log&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then you can start your session with &lt;code&gt;start_myapp&lt;/code&gt; and your layout will be ready for you. Here&amp;#8217;s a screenshot from the documentation:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/tmuxinator.jpg" alt="Tmux session" /&gt;&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s excellent documentation on using tmuxinator in the &lt;a href="https://github.com/aziz/tmuxinator/blob/master/README.md"&gt;project README&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Foreman&lt;/h2&gt;

&lt;p&gt;Enter the final piece of the jigsaw - &lt;a href="https://github.com/ddollar/foreman"&gt;foreman&lt;/a&gt;. Foreman is a gem that lets you manage background processes associated with your application through a Procfile. You just add any processes you want to be started into the Procfile and you are done. Here&amp;#8217;s an example&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Procfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;worker: bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake resque:work &lt;span class="nv"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sweep_orders
&lt;/span&gt;&lt;span class='line'&gt;apn_sender: bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake apn:sender
&lt;/span&gt;&lt;span class='line'&gt;resque_scheduler: bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake resque:scheduler
&lt;/span&gt;&lt;span class='line'&gt;resque_web: bundle &lt;span class="nb"&gt;exec &lt;/span&gt;resque-web --foreground --server thin --port &lt;span class="nv"&gt;$PORT&lt;/span&gt; --no-launch
&lt;/span&gt;&lt;span class='line'&gt;sphinx: bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rake ts:run_in_foreground
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You can then start these process by running&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Procfile&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;foreman start
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The processes will run in the foreground and spit out any logs messages to standard output - perfect for development.&lt;/p&gt;

&lt;p&gt;Using foreman you can add a tab to tmuxinator that will start your processes and have a nice log of what they are doing. We have a neat way of starting any background processes in our app within the context of our unified tmux development environment.&lt;/p&gt;

&lt;p&gt;So with one command we can set things up exactly the way we want and get straight into developing.&lt;/p&gt;

&lt;h2&gt;Alternatives&lt;/h2&gt;

&lt;p&gt;This technique will also work well for screen and regular terminal users with the &lt;a href="https://github.com/jondruse/screeninator"&gt;Screeninator&lt;/a&gt; and &lt;a href="https://github.com/achiu/terminitor"&gt;Terminitor&lt;/a&gt; gems so if you are not sold on tmux you can still use it.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/L-mcz1uLlbI" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//instant-rails-dev-environments-with-tmuxinator-and-foreman/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Building a Rails server with Puppet]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/OCOWlX8Tvi4/" />
    <updated>2011-06-22T00:00:00+01:00</updated>
    <id>http://shapeshed.com//building-a-rails-server-with-puppet</id>
    <content type="html">&lt;h2&gt;The goal&lt;/h2&gt;

&lt;p&gt;On a regular basis at &lt;a href="http://pebblecode.com/"&gt;pebble.code&lt;/a&gt; where I work we have a requirement to provision servers for clients, mostly for Rails apps. In the past we have used a combination of Cloud PaaS providers like &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt; or &lt;a href="http://www.engineyard.com/"&gt;Engine Yard&lt;/a&gt;, we have built servers manually (gasp) or used bash scripts.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.puppetlabs.com/"&gt;Puppet&lt;/a&gt; is a tool for building and managing servers and looked like a great fit for our requirements.&lt;/p&gt;

&lt;h2&gt;Learning curve&lt;/h2&gt;

&lt;p&gt;Puppet has a learning curve but there are lots of excellent resources available on the web. I found &lt;a href="http://www.amazon.com/Pulling-Strings-Puppet-Automated-Administration/dp/1590599780"&gt;Pulling Strings With Puppet&lt;/a&gt; to be an excellent resource and there is also some &lt;a href="http://docs.puppetlabs.com/"&gt;good documentation&lt;/a&gt; on the Puppet site. I&amp;#8217;ve written before on how to &lt;a href="http://shapeshed.com/journal/setting-up-puppet-on-ubuntu-10-04/"&gt;set up Puppet on Ubuntu 10.04&lt;/a&gt; and also how to &lt;a href="http://shapeshed.com/journal/connecting-clients-to-a-puppet-master/"&gt;connect clients to a Puppet master&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you learn about &lt;a href="http://docs.puppetlabs.com/learning/ral.html"&gt;resources&lt;/a&gt; and &lt;a href="http://docs.puppetlabs.com/learning/modules1.html"&gt;modules&lt;/a&gt; you are pretty much ready to get going.&lt;/p&gt;

&lt;h2&gt;Setting up Puppet Dashboard&lt;/h2&gt;

&lt;p&gt;Puppet comes with a dashboard that can be run on the Puppet Master to give a graphic view into what your nodes are doing, providing reports of updates and letting you know if there are any problems. There&amp;#8217;s some good documentation &lt;a href="http://docs.puppetlabs.com/guides/installing_dashboard.html"&gt;offered by PuppetLabs&lt;/a&gt; on this to get you started.&lt;/p&gt;

&lt;p&gt;I had some problems getting this going getting the error&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;can't activate rack (~&amp;gt; 1.0.1), already activated rack-1.2.2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;a href="http://groups.google.com/group/puppet-users/browse_thread/thread/1cd0d79a33ff9c0e"&gt;This thread&lt;/a&gt; on the puppet-users mailing list gives a fix&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;cd &amp;lt;path-to-dashboard&amp;gt; 
&lt;/span&gt;&lt;span class='line'&gt;git clone git://github.com/puppetlabs/puppet-dashboard.git 
&lt;/span&gt;&lt;span class='line'&gt;rm -r vendor/gems/rack-1.0.1 
&lt;/span&gt;&lt;span class='line'&gt;sed -i -e 's,~&amp;gt; 1.0.1,~&amp;gt; 1.2.2,' vendor/rails/actionpack/lib/action_controller.rb &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;After that I was able to see the nodes and updates.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/puppet_dashboard.jpg" alt="Puppet Dashboard" /&gt;&lt;/p&gt;

&lt;h2&gt;Rails stack choices&lt;/h2&gt;

&lt;p&gt;Then came the hard part - creating Puppet modules and using third party ones to install software on the server. I ended up writing my own for some but used existing modules where possible.&lt;/p&gt;

&lt;p&gt;The ones I found most useful in building a Rails stack were&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/blt04/puppet-rvm"&gt;puppet-rvm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jfryman/puppet-nginx"&gt;puppet-nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/puppetlabs/puppetlabs-mysql"&gt;puppetlabs-mysql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/deck/puppet-monit"&gt;puppet-monit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;One issue is where to put the responsibility for some items in the stack. The web server is a good example. In my case I chose to use Unicorn and manage the installation of this via &lt;a href="http://gembundler.com/"&gt;bundler&lt;/a&gt; and the Gemfile of the application.  I could have chosen to use Puppet for this with something like Passenger. For automation Passenger is difficult to upgrade as it needs to be recompiled against Apache or Nginx. By chosing Unicorn I can upgrade it easily using bundler. To manage Unicorn I use an &lt;a href="https://gist.github.com/750379"&gt;init&lt;/a&gt; script and hook this up to Monit and capistrano recipes. I&amp;#8217;m still not sure about this approach but it works at least.&lt;/p&gt;

&lt;h2&gt;Switching the Puppet Master to Unicorn&lt;/h2&gt;

&lt;p&gt;As the number of nodes grew, and particularly where a new node was added I found that the default WEBrick server that ships with Puppet was not good enough and I started to hit some errors. Thankfully there is an &lt;a href="http://projects.puppetlabs.com/projects/1/wiki/Using_Unicorn"&gt;excellent wiki article&lt;/a&gt; on the Puppet Labs site walking through how to switch Puppet to using &lt;a href="http://unicorn.bogomips.org/"&gt;Unicorn&lt;/a&gt;. Unicorn is a great web server and handles load balancing itself - perfect for my requirements.&lt;/p&gt;

&lt;h2&gt;Workflow&lt;/h2&gt;

&lt;p&gt;I chose to deploy using Capistrano and a git based workflow. I have an init script for the Unicorn Master powering Puppet so I can take advantage of the rolling restarts offered by Unicorn.&lt;/p&gt;

&lt;h2&gt;Still to do&amp;#8230;&lt;/h2&gt;

&lt;p&gt;I still need to create a good framework for testing. Currently I run things against a blank VM. There are a &lt;a href="http://projects.puppetlabs.com/projects/1/wiki/Branch_Testing"&gt;few&lt;/a&gt; &lt;a href="http://docs.puppetlabs.com/guides/tests_smoke.html"&gt;patterns&lt;/a&gt; for testing which I would like to become a bit more familiar with and use. I&amp;#8217;d like to extend a few existing modules and write a few new ones, particularly for user managemet.&lt;/p&gt;

&lt;h2&gt;The good bit&lt;/h2&gt;

&lt;p&gt;The good bit is that we can now create a secure, bootstrapped server that can host any rack application with any cloud provider within about 20 minutes. Moreover we can manage SSH keys with Puppet so it is easy to grant and revoke developer access.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s more to learn but in my opinion the investment of time was well worth it.&lt;/p&gt;

&lt;p&gt;After reading this article &lt;a href="http://howradical.com/"&gt;Matt Tanase&lt;/a&gt; contacted me about a great project called &lt;a href="https://github.com/devstructure/blueprint"&gt;Blueprint&lt;/a&gt;. If you are porting existing infrastructure to Puppet have a look.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/OCOWlX8Tvi4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//building-a-rails-server-with-puppet/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Building a Rails development server]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/YIX1a2YD0Ek/" />
    <updated>2011-06-06T00:00:00+01:00</updated>
    <id>http://shapeshed.com//building-a-rails-development-server</id>
    <content type="html">&lt;p&gt;At &lt;a href="http://pebblecode.com/"&gt;pebble.coe&lt;/a&gt; where I work we have a Ubuntu 10.04 LTS server for our Rails and Ruby projects. We use this mostly internally but sometimes expose sites outside of our network to allow clients to quickly review work. When we started the business we built the Rails stack using the standard tools - &lt;a href="http://www.apache.org/"&gt;Apache&lt;/a&gt; and &lt;a href="http://www.modrails.com/"&gt;Passenger&lt;/a&gt;. As our client list grew and we took on a couple of legacy projects we found that this stack no longer matched the environments that we were deploying too and didn&amp;#8217;t give us the flexibility we wanted. So here&amp;#8217;s how we changed it.&lt;/p&gt;

&lt;h2&gt;Promoting nginx to port 80&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://wiki.nginx.org/"&gt;Nginx&lt;/a&gt; is quite simply an awesome web server. It is simple to configure, the memory footprint is small and it can be used to proxy traffic through the web server of our choice and can serve static assets like html, images and css directly before it hits the Rails app.&lt;/p&gt;

&lt;p&gt;From having the ability to serve Rails sites only from Apache and Passenger we have moved to this.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/nginx_proxy_diagram.png" alt="Nginx Proxy Diagram" /&gt;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ve moved Apache to port 81 so if a site needs to be tested on that setup we can still do it. Otherwise we can proxy from nginx directly to Apache. The real flexibility comes from the server we use to serve the Rails app. We deploy by choice on &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt; or &lt;a href="http://unicorn.bogomips.org/"&gt;Unicorn&lt;/a&gt; so we can replicate this stack easily. We are looking at &lt;a href="http://postrank-labs.github.com/goliath/"&gt;Goliath&lt;/a&gt; at the moment so we could easily add this in beneath Nginx. We are playing with some other technologies like &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; too. With Nginx we can support this too.&lt;/p&gt;

&lt;h2&gt;Getting nginx&lt;/h2&gt;

&lt;p&gt;If you want to make the switch on Ubuntu there is a PPA repo you can add&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo -s
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stable &lt;span class="c"&gt;# use nginx=development for latest development version&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;add-apt-repository ppa:nginx/&lt;span class="nv"&gt;$nginx&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;apt-get update
&lt;/span&gt;&lt;span class='line'&gt;apt-get install nginx
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you are currently using Apache you&amp;#8217;ll need to decide whether or not to keep it on port 80. We switched Apache to port 81 and promoted Nginx to port 80.&lt;/p&gt;

&lt;h2&gt;Example configs&lt;/h2&gt;

&lt;p&gt;The Ubuntu install uses &lt;code&gt;sites-available&lt;/code&gt; and &lt;code&gt;sites-enabled&lt;/code&gt; folders to allow you to create site configs. Here are some examples that you can use to get you started.&lt;/p&gt;

&lt;p&gt;Logs are disabled in these examples. If you want logging just add a path to the log file.&lt;/p&gt;

&lt;h3&gt;Default proxy settings&lt;/h3&gt;

&lt;p&gt;To keep your Nginx configs nice and DRY you can add a file to hold common proxy settings under &lt;code&gt;/etc/nginx/conf.d&lt;/code&gt; called in my case proxy.conf&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;proxy.conf&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_redirect&lt;/span&gt;     &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt;   &lt;span class="s"&gt;Host&lt;/span&gt;             &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt;   &lt;span class="s"&gt;X-Real-IP&lt;/span&gt;        &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_set_header&lt;/span&gt;   &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;  &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_max_temp_file_size&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;client_max_body_size&lt;/span&gt;       &lt;span class="mi"&gt;10m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;client_body_buffer_size&lt;/span&gt;    &lt;span class="mi"&gt;128k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_connect_timeout&lt;/span&gt;      &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_send_timeout&lt;/span&gt;         &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_read_timeout&lt;/span&gt;         &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_buffer_size&lt;/span&gt;          &lt;span class="mi"&gt;4k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_buffers&lt;/span&gt;              &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="mi"&gt;32k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_busy_buffers_size&lt;/span&gt;    &lt;span class="mi"&gt;64k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;proxy_temp_file_write_size&lt;/span&gt; &lt;span class="mi"&gt;64k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Proxy to Apache&lt;/h3&gt;

&lt;p&gt;This expects that you have setup an Apache virtual host on port 81.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Nginx proxy to Apache&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server_name&lt;/span&gt;  &lt;span class="s"&gt;site1.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;access_log&lt;/span&gt;  &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;error_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt;         &lt;span class="s"&gt;http://127.0.0.1:81/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Proxy to Thin&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Nginx proxy to Thin&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;thin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="s"&gt;unix:/var/www/vhosts/site2.com/httpdocs/current/tmp/sockets/thin.0.sock&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server_name&lt;/span&gt;  &lt;span class="s"&gt;site2.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;access_log&lt;/span&gt;  &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;error_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt;         &lt;span class="s"&gt;http://thin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Proxy to Unicorn&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Nginx proxy to Thin&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;unicorn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="s"&gt;unix:/var/www/vhosts/site3.com/httpdocs/current/tmp/sockets/unicorn.sock&lt;/span&gt; &lt;span class="s"&gt;fail_timeout=0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;listen&lt;/span&gt;       &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server_name&lt;/span&gt;  &lt;span class="s"&gt;site3.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;access_log&lt;/span&gt;  &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;error_log&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt;         &lt;span class="s"&gt;http://unicorn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;So which one is best?&lt;/h2&gt;

&lt;p&gt;Having played a fair bit recently with servers to serve up Rails apps there isn&amp;#8217;t a clear answer I&amp;#8217;m afraid. I may get round to publishing my rudimentary benchmarks but I&amp;#8217;ve found that for low memory deployments Nginx and Thin is a great choice. The response times are excellent and memory usage is much lower than Passenger or Unicorn. Thin doesn&amp;#8217;t come with the same in-built load balancing that you get with Unicorn so &lt;a href="http://haproxy.1wt.eu/"&gt;HAProxy&lt;/a&gt; comes in to play here. HAProxy is another piece in the stack though which may put some off.&lt;/p&gt;

&lt;p&gt;If memory isn&amp;#8217;t an issue then Unicorn behind Nginx is a great choice. The rolling deployments are a great feature, but you also get free load balancing with Unicorn thanks to the &lt;a href="http://tomayko.com/writings/unicorn-is-unix"&gt;power of UNIX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are not interested in memory or tweaking you are probably best with Passenger behind Nginx.&lt;/p&gt;

&lt;p&gt;If you are not interested in doing any sys admin work use &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt;, &lt;a href="http://www.engineyard.com/"&gt;EngineYard&lt;/a&gt; or &lt;a href="http://www.brightbox.co.uk/"&gt;Brightbox&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you are rolling your own servers and using Apache switch to Nginx!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/YIX1a2YD0Ek" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//building-a-rails-development-server/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Creating a basic site with node.js and Express]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/ZW-4_oJrF74/" />
    <updated>2011-04-18T00:00:00+01:00</updated>
    <id>http://shapeshed.com//creating-a-basic-site-with-node-and-express</id>
    <content type="html">&lt;h2&gt;What we are going to do&lt;/h2&gt;

&lt;p&gt;This walkthrough will go over setting up a basic site using &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; and Express. The walkthrough is aimed at beginners exploring node.js as I&amp;#8217;ve had many questions from friends and colleagues about creating and deploying node apps. If you are not a beginner the article probably won&amp;#8217;t be of much use to you. We are going to use &lt;a href="http://expressjs.com/"&gt;express&lt;/a&gt;, an excellent web framework for node created by &lt;a href="http://tjholowaychuk.com/"&gt;TJ Holowaychuk&lt;/a&gt; who seems to be pumping out node.js libraries like he was ten men.&lt;/p&gt;

&lt;p&gt;Here is &lt;a href="http://express_example.nodester.com"&gt;the site&lt;/a&gt; we are going to create. You might also want to grab the &lt;a href="https://github.com/shapeshed/express_example"&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://express_example.nodester.com"&gt;&lt;img src="http://shapeshed.com/images/articles/express_example.jpg" alt="Example Express website" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Setup&lt;/h2&gt;

&lt;p&gt;First we need to setup our development environment. If you are on OSX I&amp;#8217;ve &lt;a href="http://shapeshed.com/journal/setting-up-nodejs-and-npm-on-mac-osx/"&gt;covered how to setup node.js and npm on OSX&lt;/a&gt; in a previous article. If you haven&amp;#8217;t got everything installed follow that article.&lt;/p&gt;

&lt;p&gt;If you are on Linux there are plenty of &lt;a href="http://www.google.com/search?q=install+node.js+linux"&gt;articles on Google&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Windows users there are also &lt;a href="http://www.google.com/search?q=install+node.js+windows"&gt;resources on Google&lt;/a&gt; but it is a bit more tricky.&lt;/p&gt;

&lt;h2&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;If everything has installed ok you should now have node.js and npm running on your machine. At the terminal type &lt;code&gt;node -v&lt;/code&gt; and &lt;code&gt;npm -v&lt;/code&gt; and you should see something like:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;node -v
&lt;/span&gt;&lt;span class='line'&gt;v0.4.5
&lt;/span&gt;&lt;span class='line'&gt;npm -v
&lt;/span&gt;&lt;span class='line'&gt;1.0.1rc7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You&amp;#8217;ll see I&amp;#8217;m using the RC of version 1 of npm. I encourage you to install this as this will soon become the default.&lt;/p&gt;

&lt;h2&gt;Create an Express site&lt;/h2&gt;

&lt;p&gt;Still with me? We&amp;#8217;ve covered a lot already! Now let&amp;#8217;s create an Express site.&lt;/p&gt;

&lt;p&gt;First let&amp;#8217;s create a folder for our project and install Express.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;mkdir express_example
&lt;/span&gt;&lt;span class='line'&gt;cd express_example
&lt;/span&gt;&lt;span class='line'&gt;npm install express&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This installs Express into the directory we created. Now we can create the skeleton site. We are going to use &lt;a href="http://jade-lang.com/"&gt;jade&lt;/a&gt; and &lt;a href="http://learnboost.github.com/stylus/"&gt;stylus&lt;/a&gt; for templating and css. More on those later.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;./node_modules/express/bin/express -t jade -c stylus
&lt;/span&gt;&lt;span class='line'&gt;destination is not empty, continue? y
&lt;/span&gt;&lt;span class='line'&gt;   create : .
&lt;/span&gt;&lt;span class='line'&gt;   create : ./app.js
&lt;/span&gt;&lt;span class='line'&gt;   create : ./public/stylesheets
&lt;/span&gt;&lt;span class='line'&gt;   create : ./public/stylesheets/style.styl
&lt;/span&gt;&lt;span class='line'&gt;   create : ./public/images
&lt;/span&gt;&lt;span class='line'&gt;   create : ./public/javascripts
&lt;/span&gt;&lt;span class='line'&gt;   create : ./logs
&lt;/span&gt;&lt;span class='line'&gt;   create : ./pids
&lt;/span&gt;&lt;span class='line'&gt;   create : ./test
&lt;/span&gt;&lt;span class='line'&gt;   create : ./test/app.test.js
&lt;/span&gt;&lt;span class='line'&gt;   create : ./views
&lt;/span&gt;&lt;span class='line'&gt;   create : ./views/layout.jade
&lt;/span&gt;&lt;span class='line'&gt;   create : ./views/index.jade
&lt;/span&gt;&lt;span class='line'&gt;   - make sure you have installed stylus: $ npm install stylus
&lt;/span&gt;&lt;span class='line'&gt;   - make sure you have installed jade: $ npm install jade&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You&amp;#8217;ll see that we need to install a couple of dependencies for stylus and jade support so let&amp;#8217;s do that.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;npm install stylus jade&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Boot the app&lt;/h2&gt;

&lt;p&gt;That&amp;#8217;s all the setup you need. Phew. Now you can boot the app:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;node app.js&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You should see &lt;code&gt;Express server listening on port 3000&lt;/code&gt; and if you open http://0.0.0.0:3000 you&amp;#8217;ll see the default Express page.&lt;/p&gt;

&lt;h2&gt;Using Git&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; is a version control system that is used heavily in the node.js ecosystem, particulary with &lt;a href="https://github.com/"&gt;Github&lt;/a&gt;. If you aren&amp;#8217;t familiar with Git &lt;a href="http://scottchacon.com/"&gt;Scott Chacon&lt;/a&gt; is your go-to man. He&amp;#8217;s written extensively and eloquently on Git for beginners and experts. Checkout &lt;a href="http://gitcasts.com/"&gt;Gitcasts&lt;/a&gt; for if you are a beginner and &lt;a href="http://progit.org/"&gt;ProGit&lt;/a&gt; for more advanced stuff. We are going to use git to version our site and publish it so let&amp;#8217;s set up our repo now. If your Express server is still running hit CTRL + C to stop it.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;git init
&lt;/span&gt;&lt;span class='line'&gt;git add .
&lt;/span&gt;&lt;span class='line'&gt;git commit -m 'initial commit'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Developing node.js sites&lt;/h2&gt;

&lt;p&gt;Normally when you develop a node.js site you&amp;#8217;ll need ot restart your application each time you make a change. Thankfully our home-grown British JavaScript genius &lt;a href="http://remysharp.com/"&gt;Remy Sharp&lt;/a&gt; has solved this problem with &lt;a href="https://github.com/remy/nodemon"&gt;nodemon&lt;/a&gt;. Nodemon will reload your application each time it changes so you don&amp;#8217;t need to restart it. If you have used &lt;a href="https://github.com/rtomayko/shotgun"&gt;Shotgun&lt;/a&gt; for Ruby with &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt; it is similar to that. To install run&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;npm install -g nodemon&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then you can start your app with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;nodemon app.js&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Using nodemon means you don&amp;#8217;t have to restart your app each time you make a change. For more infomation on nodemon see the &lt;a href="https://github.com/remy/nodemon/blob/master/README.md"&gt;README&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;HTML in Express&lt;/h2&gt;

&lt;p&gt;Express is agnostic as to which templating language you use. Templating languages can be a hot topic of debate but for this article I&amp;#8217;m going to use &lt;a href="http://jade-lang.com/"&gt;jade&lt;/a&gt;. If you&amp;#8217;ve used &lt;a href="http://haml-lang.com/"&gt;haml&lt;/a&gt; it is similar to that. In the example we use jade to setup a layout template.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='jade'&gt;&lt;span class='line'&gt;&lt;span class="nn"&gt;!!! 5&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;html&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;head&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;link&lt;/span&gt;(&lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/stylesheets/style.css&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;link&lt;/span&gt;(&lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;stylesheet&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/stylesheets/chunkfive-fontface.css&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;header&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nt"&gt;nav&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;ul&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nt"&gt;li&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nt"&gt;a&lt;/span&gt;(&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;) Home
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nt"&gt;li&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nt"&gt;a&lt;/span&gt;(&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/about&amp;quot;&lt;/span&gt;) About
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nt"&gt;li&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nt"&gt;a&lt;/span&gt;(&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/contact&amp;quot;&lt;/span&gt;) Contact
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nf"&gt;#wrapper&lt;/span&gt;&lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="nt"&gt;footer&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;          &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.css-table&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;            &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.four-column&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;              &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.cell&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nt"&gt;p&lt;/span&gt; Mauris porttitor &amp;lt;br /&amp;gt;felis eu leo aliquet&amp;lt;br /&amp;gt; ac rutrum odio aliquet
&lt;/span&gt;&lt;span class='line'&gt;              &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.cell&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nt"&gt;p&lt;/span&gt; Mauris porttitor &amp;lt;br /&amp;gt;felis eu leo aliquet&amp;lt;br /&amp;gt; ac rutrum odio aliquet
&lt;/span&gt;&lt;span class='line'&gt;              &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.cell&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nt"&gt;p&lt;/span&gt; Mauris porttitor &amp;lt;br /&amp;gt;felis eu leo aliquet&amp;lt;br /&amp;gt; ac rutrum odio aliquet
&lt;/span&gt;&lt;span class='line'&gt;              &lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="nc"&gt;.cell&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;                &lt;span class="nt"&gt;p&lt;/span&gt; Mauris porttitor &amp;lt;br /&amp;gt;felis eu leo aliquet&amp;lt;br /&amp;gt; ac rutrum odio aliquet
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is a common template we can reuse. The line &lt;code&gt;section#wrapper!= body&lt;/code&gt; pulls in content from the page it is used on. Express also supports variables that you pass through to the template. In this case we pass the title variable. If you are coming from Sinatra this will all be familiar to you. If you are not I recommend consulting the &lt;a href="http://expressjs.com/guide.html"&gt;Express documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;CSS in Express&lt;/h2&gt;

&lt;p&gt;Again Express is agnostic to what you use to generate your CSS - you can use vanilla CSS but for this example I&amp;#8217;m using &lt;a href="http://learnboost.github.com/stylus/"&gt;Stylus&lt;/a&gt;. This is very similar to &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; and supports variables, mixins, functions and more. I really like it! Here&amp;#8217;s an example from our stylesheet&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='jade'&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;font&lt;/span&gt; 62.5%/1.5  Helvetica, Arial, &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Lucida Sans&amp;quot;, Tahoma, Verdana, sans-serif
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;text-align&lt;/span&gt; center
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;background&lt;/span&gt; #000
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nf"&gt;#wrapper&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;width&lt;/span&gt; 920px
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;text-align&lt;/span&gt; left
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;margin-left&lt;/span&gt; auto
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;margin-right&lt;/span&gt; auto
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;background&lt;/span&gt; #fff
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;padding&lt;/span&gt; 20px
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;border-bottom-radius&lt;/span&gt;(&lt;span class="na"&gt;15px&lt;/span&gt;)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You&amp;#8217;ll see that stylus is very terse - you don&amp;#8217;t need brackets or commas.&lt;/p&gt;

&lt;h2&gt;Routing in Express&lt;/h2&gt;

&lt;p&gt;Routing is similar to &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt;, allowing you to set up RESTful routes.&lt;/p&gt;

&lt;p&gt;In this example we setup three routes in &lt;a href="https://github.com/shapeshed/express_example/blob/master/app.js"&gt;app.js&lt;/a&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Home&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/about&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;about&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;About&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/contact&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;contact&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Contact&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;See the &lt;a href="http://expressjs.com/guide.html#routing"&gt;Express documentation&lt;/a&gt; for more.&lt;/p&gt;

&lt;h2&gt;Publishing your site&lt;/h2&gt;

&lt;p&gt;We&amp;#8217;ve now developed a basic node.js site using express and we want to host it somewhere.&lt;/p&gt;

&lt;p&gt;There are a number of hosting options for node. It isn&amp;#8217;t so difficult to host it yourself but for me the easiest and best is &lt;a href="http://nodester.com/"&gt;Nodester&lt;/a&gt;. If you have used &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt; the deployment process is very similar. You&amp;#8217;ll need to request an invite for Nodester (it won&amp;#8217;t come through immediately though).&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;curl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;email=your_address@gmail.com&amp;quot;&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//nodester.com/coupon&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;a href="http://chrismatthieu.com/"&gt;Chris Matthieu&lt;/a&gt; has created a &lt;a href="http://www.youtube.com/watch?v=IMCXbrI_Ygk"&gt;handy video&lt;/a&gt; going over how to deploy to Nodester so go and watch that if you don&amp;#8217;t fancy reading the &lt;a href="http://nodester.com/api.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s create the site on nodester&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;express_example&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now we can get the information on the site&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="nx"&gt;express_example&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="nx"&gt;Gathering&lt;/span&gt; &lt;span class="nx"&gt;information&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;express_example&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;warn&lt;/span&gt; &lt;span class="nx"&gt;express_example&lt;/span&gt; &lt;span class="nx"&gt;on&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="mi"&gt;9451&lt;/span&gt; &lt;span class="nx"&gt;running&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="nx"&gt;gitrepo&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="err"&gt;/node/hosted_apps/shapeshed/1298-ec0117a54b696d7a9781c79e5283692e.git&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="nx"&gt;appfile&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;To publish the site we need to add the git repo as a remote our git repo&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;remote&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;nodester&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="err"&gt;/node/hosted_apps/shapeshed/1298-ec0117a54b696d7a9781c79e5283692e.git&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And finally we can publish the site by pushing&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="nx"&gt;nodester&lt;/span&gt; &lt;span class="nx"&gt;master&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Nodester will let you know about the deploy - if the deploy was successful you can see your app at http://[your_app_name].nodester.com/. In this example you can see the site at &lt;a href="http://express_example.nodester.com"&gt;http://express_example.nodester.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some other node.js hosting providers include &lt;a href="http://www.nodejitsu.com/"&gt;nodejitsu&lt;/a&gt;, &lt;a href="https://no.de/"&gt;Joyent&lt;/a&gt;, &lt;a href="http://www.cloudfoundry.com/"&gt;Cloud Foundry&lt;/a&gt; and &lt;a href="http://www.duostack.com/"&gt;Duostack&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This article has showed how to create a very basic site using node.js and Express. It has introduced a number of things from the node.js ecosystem and showed you how to deploy your app to Nodester.&lt;/p&gt;

&lt;p&gt;The strengths of node.js as a technology are not so much in building static websites like this. I encourage you to explore some of the node.js libraries to see what it can do. Particularly for real-time applications node.js is extremely exciting and I think we&amp;#8217;ll see some great apps built on node.js. Try starting with &lt;a href="http://socket.io/"&gt;socket.io&lt;/a&gt; for a taste of what to expect.&lt;/p&gt;

&lt;p&gt;If you find any inaccuracies in the post &lt;a href="http://shapeshed.com/contact/"&gt;send me an email&lt;/a&gt; and I&amp;#8217;ll update the post.&lt;/p&gt;

&lt;h2&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://expressjs.com/"&gt;express - node web framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://npmjs.org/"&gt;npm - node package manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jade-lang.com/"&gt;jade - node.js templating language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://learnboost.github.com/stylus/"&gt;stylus - node.js css framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://shapeshed.com/journal/setting-up-nodejs-and-npm-on-mac-osx/"&gt;Setting up node.js and npm on Mac OSX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nodester.com/"&gt;Nodester - Open Source Hosting for node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shapeshed/express_example"&gt;Source code for this article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/ZW-4_oJrF74" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//creating-a-basic-site-with-node-and-express/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Cloud Foundry - a Ruby and node.js developer's perspective]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/IqvsjYw0kLA/" />
    <updated>2011-04-15T00:00:00+01:00</updated>
    <id>http://shapeshed.com//cloud-foundry-a-ruby-and-nodejs-developers-perspective</id>
    <content type="html">&lt;h2&gt;Open Source PaaS&lt;/h2&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/cloud_foundry.jpg" alt="Cloud Foundry" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt; this week announced &lt;a href="http://cloudfoundry.com/"&gt;Cloud Foundry&lt;/a&gt;, an open source &lt;a href="http://en.wikipedia.org/wiki/Platform_as_a_service"&gt;PaaS&lt;/a&gt;. You can use VMware&amp;#8217;s cloud (which is where they&amp;#8217;ll monetise this investment) or you can host your own. I believe you can even have a hybrid of both. Cloud Foundry joins other players in the market like &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;, &lt;a href="http://www.joyent.com/"&gt;Joyent&lt;/a&gt;, &lt;a href="http://www.engineyard.com/"&gt;Engine Yard&lt;/a&gt; and &lt;a href="http://nodester.com/"&gt;Nodester&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Why PaaS?&lt;/h2&gt;

&lt;p&gt;Developers don&amp;#8217;t want to be Sys Admins. Especially in small businesses developers take on a lot - some or all of business analysis / requirements gathering, server admin, development, testing, design, client management. The list goes on. So the emergence of services like Heroku for &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; and Nodester for &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; is very attractive. Developers can remove one thing from the list of things that they need to be responsible for. It is an easy sell to the management layer too - it is cheaper in terms of man hours, with (almost) no maintenance.&lt;/p&gt;

&lt;p&gt;The providers doing well in the market are the ones that realise that developers have the keys to the choices that get made. Heroku has built a kick-ass platform with a super slick API. Frankly it is a joy to use. Nodester emerged from nowhere as an open-source weekend project and for me is beating players like Joyent in their node.js offering.&lt;/p&gt;

&lt;h2&gt;One Paas to rule them all?&lt;/h2&gt;

&lt;p&gt;VMware have put considerable effort into building a PaaS to accommodate three technologies - Java, Ruby and node.js. They must be applauded for open-sourcing the project and making it available on &lt;a href="https://github.com/cloudfoundry"&gt;GitHub&lt;/a&gt;. There are a considerable amount of man hours there and a significant investment from VMware. Thank you.&lt;/p&gt;

&lt;h2&gt;Taking it for a spin&lt;/h2&gt;

&lt;p&gt;So I took it for a spin firing up a &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; &lt;a href="http://releases.ubuntu.com/lucid/"&gt;Ubuntu 10.04.2 LTS&lt;/a&gt; VM. Installation was simple enough following the &lt;a href="https://github.com/cloudfoundry/vcap/blob/master/README"&gt;README&lt;/a&gt;.  I created the SSH tunnel as advised and within about half an hour had built a private cloud capable of running Java, Ruby and node.js apps, with support for MySQL, Redis and MongoDB. Impressive.&lt;/p&gt;

&lt;p&gt;The VMware team have thought hard about the API. If you are a RubyGems user you can check it out by installing the vmc rubygem and then running help&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Installing the vmc gem&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;gem install vmc --no-ri --no-rdoc
&lt;/span&gt;&lt;span class='line'&gt;vmc --help
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Once you have setup a user on your private cloud deploying an app is super simple. Here&amp;#8217;s the process of deploying an app&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Deploying with vmc&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;vmc push &lt;span class="o"&gt;[&lt;/span&gt;yourappname&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Err.. that&amp;#8217;s it. Amazing!&lt;/p&gt;

&lt;h2&gt;Testing deployment on my cloud&lt;/h2&gt;

&lt;p&gt;Then I set about deploying a node.js app. It was a simple express based node.js application with express, jade and stylus as dependencies. So let&amp;#8217;s give it a go&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Deploying a Node.js app&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;vmc push myapp
&lt;/span&gt;&lt;span class='line'&gt;Would you like to deploy from the current directory? &lt;span class="o"&gt;[&lt;/span&gt;Yn&lt;span class="o"&gt;]&lt;/span&gt;: y
&lt;/span&gt;&lt;span class='line'&gt;Application Deployed URL: &lt;span class="s1"&gt;&amp;#39;myapp.vcap.me&amp;#39;&lt;/span&gt;?
&lt;/span&gt;&lt;span class='line'&gt;Detected a Node.js Application, is this correct? &lt;span class="o"&gt;[&lt;/span&gt;Yn&lt;span class="o"&gt;]&lt;/span&gt;: y
&lt;/span&gt;&lt;span class='line'&gt;Memory Reservation &lt;span class="o"&gt;[&lt;/span&gt;Default:64M&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;64M, 128M, 256M, 512M, 1G or 2G&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;Creating Application: OK
&lt;/span&gt;&lt;span class='line'&gt;Would you like to &lt;span class="nb"&gt;bind &lt;/span&gt;any services to &lt;span class="s1"&gt;&amp;#39;myapp&amp;#39;&lt;/span&gt;? &lt;span class="o"&gt;[&lt;/span&gt;yN&lt;span class="o"&gt;]&lt;/span&gt;: n
&lt;/span&gt;&lt;span class='line'&gt;Uploading Application:
&lt;/span&gt;&lt;span class='line'&gt;  Checking &lt;span class="k"&gt;for &lt;/span&gt;available resources: OK
&lt;/span&gt;&lt;span class='line'&gt;  Processing resources: OK
&lt;/span&gt;&lt;span class='line'&gt;  Packing application: OK
&lt;/span&gt;&lt;span class='line'&gt;  Uploading &lt;span class="o"&gt;(&lt;/span&gt;613K&lt;span class="o"&gt;)&lt;/span&gt;: OK
&lt;/span&gt;&lt;span class='line'&gt;Push Status: OK
&lt;/span&gt;&lt;span class='line'&gt;Staging Application: OK
&lt;/span&gt;&lt;span class='line'&gt;Starting Application: ..........................Error 306: Error retrieving file &lt;span class="s1"&gt;&amp;#39;logs/startup.log&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It failed. I used the log commands but there wasn&amp;#8217;t any useful output - I guess this is early days. But I did find &lt;a href="http://support.cloudfoundry.com/entries/505133-deploying-a-node-js-app-with-npm-dependencies"&gt;this article&lt;/a&gt; which required changing a couple of things in the app file. After that it was as easy as&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;vmc update myapp
&lt;/span&gt;&lt;span class='line'&gt;Uploading Application:
&lt;/span&gt;&lt;span class='line'&gt;  Checking &lt;span class="k"&gt;for &lt;/span&gt;available resources: OK
&lt;/span&gt;&lt;span class='line'&gt;  Processing resources: OK
&lt;/span&gt;&lt;span class='line'&gt;  Packing application: OK
&lt;/span&gt;&lt;span class='line'&gt;  Uploading &lt;span class="o"&gt;(&lt;/span&gt;15K&lt;span class="o"&gt;)&lt;/span&gt;: OK
&lt;/span&gt;&lt;span class='line'&gt;Push Status: OK
&lt;/span&gt;&lt;span class='line'&gt;Stopping Application: OK
&lt;/span&gt;&lt;span class='line'&gt;Staging Application: OK
&lt;/span&gt;&lt;span class='line'&gt;Starting Application: OK
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Lovely! The API follows exactly the same process for deploying a Sinatra / Rails which is really attractive.&lt;/p&gt;

&lt;p&gt;At &lt;a href="http://pebblecode.com"&gt;pebble.code&lt;/a&gt; where I work I&amp;#8217;m responsible for managing servers and setting up development sites for the team. This can be a time-consuming chore and I&amp;#8217;ve been working towards a &lt;a href="http://www.puppetlabs.com/"&gt;Puppet&lt;/a&gt; setup to allow me to automate much of this. A private cloud where developers can spin up apps with three words is massively better.&lt;/p&gt;

&lt;h2&gt;What&amp;#8217;s good about Cloud Foundry&lt;/h2&gt;

&lt;p&gt;I love the fact that VMware understand that PaaS is about being open and not being tied to one platform. Being open makes me more likely to use a platform than one that makes it hard for me to get my data in and out. I can easily move my apps in and out at any time. I can create my own cloud and move my apps onto that. I&amp;#8217;m free and I like that.&lt;/p&gt;

&lt;p&gt;I love the fact that Cloud Foundry is open source and created using Ruby. The Ruby community is full of talented and smart developers and it is a wise move by VMware to engage that community. I anticipate the product will be enhanced by open source contributions.&lt;/p&gt;

&lt;h2&gt;What could be improved&lt;/h2&gt;

&lt;p&gt;It is a real shame that VMware didn&amp;#8217;t go with &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; based deployment. Both the Ruby/Rails and node.js communities use git heavily and are used to git based PaaS services. I&amp;#8217;m not sure why this design decision was made - perhaps the old skool Java heads at VMware won out. It would be great to see git deployment added to the platform. Currently there is no versioning on the platform - it would be a quick feature win to leverage the power of git to add this.&lt;/p&gt;

&lt;p&gt;That said with the project being open source the developer community can easily fork it and enhance the platform. The fact that the project is open source is massive.&lt;/p&gt;

&lt;h2&gt;Will I use it?&lt;/h2&gt;

&lt;p&gt;Maybe. Currently I&amp;#8217;m happy with the PaaS providers I&amp;#8217;m using - &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt; and &lt;a href="http://nodester.com/"&gt;Nodester&lt;/a&gt;. I feel both are doing a great job. Heroku is closed source, whilst Nodester is open-source. I have the option to host a Nodester private cloud somewhere but Cloud Foundry is the only solution to offer both Ruby and node.js. I like that. Currently I mostly use PaaS providers for quickly prototyping an idea and getting it out there. I could see a Cloud Foundry private cloud working well for this.&lt;/p&gt;

&lt;p&gt;The API is a big thing for me and I think VMware has done a great job here. Where Heroku has led others have followed and that&amp;#8217;s great news for developers.&lt;/p&gt;

&lt;p&gt;But.. for many of our production apps they have more complex technical architectures involving Resque, Redis, Sphinx, cron jobs and background processes. In short we need to have full control over the server. Cloud Foundry goes a long way to solving this by offering MongoDB and Redis but currently unless I&amp;#8217;m mistaken I&amp;#8217;d be unable to host apps with complex requirements. This is an issue with PaaS in general. Heroku&amp;#8217;s add-ons solve most of this issue but there are times when simply you need root access.&lt;/p&gt;

&lt;p&gt;So overall thank you VMware! I also need to say thank you for your support of &lt;a href="http://redis.io/"&gt;Redis&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;What are you waiting for? &lt;a href="http://cloudfoundry.com/"&gt;Give it a go&lt;/a&gt;, or &lt;a href="https://github.com/cloudfoundry"&gt;fork it&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Further Reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cloudfoundry.com/"&gt;Cloud Foundry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nodester.com/"&gt;Nodester&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cloudfoundry"&gt;Cloud Foundry Source Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/IqvsjYw0kLA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//cloud-foundry-a-ruby-and-nodejs-developers-perspective/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Vim eighteen months on]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/MXkEd5n-B68/" />
    <updated>2011-04-12T00:00:00+01:00</updated>
    <id>http://shapeshed.com//vim-eighteen-months-on</id>
    <content type="html">&lt;h2&gt;Goodbye TextMate?&lt;/h2&gt;

&lt;p&gt;About 18 months ago I made the decision to give Vim a go as my primary text editor. I had been using vi extensively for server admin work for a number of years so I wasn&amp;#8217;t a total noob. TextMate was my default editor and broadly I was happy with it but decided to give Vim a go.&lt;/p&gt;

&lt;h2&gt;Baby steps&lt;/h2&gt;

&lt;p&gt;I started out with baby steps, looking back to TextMate and doing all of the common things a switcher does, especially looking for TextMate&amp;#8217;s features in Vim. Vim&amp;#8217;s contexts were familiar to me from working on servers so I was at an advantage there but I quickly found Derek Wyatt&amp;#8217;s &lt;a href="http://vimeo.com/user1690209/videos"&gt;awesome video series on Vim&lt;/a&gt;. Derek&amp;#8217;s videos were one of the main reasons my adoption was so positive. If you are thinking of switching to Vim I strongly recommend this resource. The videos start at a beginner level and work through to advanced techniques, are excellently produced and give a particular helping hand for newcomers. If you&amp;#8217;ve never used Vim the &lt;a href="http://vimeo.com/6999927"&gt;Welcome to Vim&lt;/a&gt; video is the best.&lt;/p&gt;

&lt;p&gt;Many people recommend using &lt;a href="http://code.google.com/p/macvim/"&gt;MacVim&lt;/a&gt; to ease the transition. &lt;a href="http://henrik.nyh.se/"&gt;Henrik Nyh&lt;/a&gt; has a great article on &lt;a href="http://henrik.nyh.se/2011/01/textmate-to-vim-with-training-wheels"&gt;switching from TextMate using MacVim&lt;/a&gt;. I didn&amp;#8217;t follow this route but it may be helpful to some.&lt;/p&gt;

&lt;p&gt;Installation of MacVim via &lt;a href="https://github.com/mxcl/homebrew"&gt;homebrew&lt;/a&gt; on OSX is easy&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;Installing macvim&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install macvim
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;MacVim works like a standard application so you don&amp;#8217;t need to edit directly in the terminal and comes with many common keyboard shortcuts that you&amp;#8217;ll likely be used to.&lt;/p&gt;

&lt;h2&gt;The setup phase&lt;/h2&gt;

&lt;p&gt;As with with many things in UNIX you get back what you put in. The &lt;a href="http://en.wikipedia.org/wiki/RTFM"&gt;RTFM&lt;/a&gt; mantra is true for Vim - it has massive and excellent documentation that you could spend months going through. The default install of Vim needs to be configured which takes time. Initially I scoured github for dotfiles and basically took configuration from developers that I admire - &lt;a href="https://github.com/tpope/tpope"&gt;Tim Pope&lt;/a&gt; and &lt;a href="https://github.com/mislav/dotfiles"&gt;Mislav Marohni&amp;#263;&lt;/a&gt;. I tweaked a little here and there, marrying up a color scheme with my terminal color scheme of choice &lt;a href="http://blog.toddwerth.com/entries/show/6"&gt;ir_black&lt;/a&gt;. If you want to pick through my dotfiles &lt;a href="https://github.com/shapeshed/dotfiles"&gt;they are here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pretty much after that I had a text editor that looked good, had sensible defaults for web programming and recognised the file formats I was editing. Then came the hard bit - getting to intermediate level.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/vim_screenshot.png" alt="Screenshot of Vim" /&gt;&lt;/p&gt;

&lt;h2&gt;Learn as you go&lt;/h2&gt;

&lt;p&gt;Vim does take time to learn. Initially it would be fair to say that I became slower. Probably for around a month. But as you go you quickly learn how Vim works and are delighted by the time-saving over other editors in almost every feature. Learning to stop using the mouse is a paradigm shift but one I highly recommend. When you get to a stage where you can quickly split windows and navigate round without using a mouse you&amp;#8217;ll see the light. I challenge anyone to commit Vim&amp;#8217;s many commands to muscle memory but the more you work with Vim the more it becomes automatic and that&amp;#8217;s where Vim&amp;#8217;s power lies.&lt;/p&gt;

&lt;p&gt;My tip is to take a little at a time and when you come up against a common problem read the manual and learn how to do. For example you might want to lowercase some text. You could do this through deleting the text and rewriting it or you could you use Vim&amp;#8217;s excellent help to learn how Vim does it:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;:help lowercase
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/lowercase_vim_help.png" alt="Screenshot of Vim's help showing lowercase entry" /&gt;&lt;/p&gt;

&lt;p&gt;This takes you straight to the documentation where you can learn the keystrokes that Vim uses before doing it in a split window context. Typically it takes me four or five lookups before I remember what the keystrokes are. If I ever forget looking it up again in the help text is so easy it is not an issue.&lt;/p&gt;

&lt;p&gt;Around about the time I was moving from a novice to intermediate Vim user &lt;a href="http://vimcasts.org/"&gt;Vimcasts&lt;/a&gt; arrived on the scene. &lt;a href="http://drewneil.com/"&gt;Drew Neil&lt;/a&gt; produces high quality screencasts on all aspects of using Vim and I highly recommend this resource. A book is also apparently in the offing from this sage so stay tuned for more from Drew.&lt;/p&gt;

&lt;h2&gt;Pumping iron, building muscle memory&lt;/h2&gt;

&lt;p&gt;The more you use Vim the more you build on your muscle memory. More and more I&amp;#8217;m finding I consult the documentation less and just do it. In short I&amp;#8217;m starting to feel like I&amp;#8217;m over the hump and am seeing the many benefits of the learning stage. But it would be fair to say that I had to pump a lot of iron to get to this stage. Months 6 - 12 were a big learning curve in that respect, and I&amp;#8217;m still learning all the time. I don&amp;#8217;t feel I&amp;#8217;ll ever learn everything about Vim but I now feel I&amp;#8217;m at a stage where I know how to get better.&lt;/p&gt;

&lt;h2&gt;Now&lt;/h2&gt;

&lt;p&gt;Fast forward 18 months and I feel I would be significantly less productive without using Vim not just for coding but also for text editing. So I can use vim for writing emails I now use &lt;a href="http://www.mutt.org/"&gt;Mutt&lt;/a&gt;, a lightweight powerful email client for the terminal. I use the &lt;a href="https://chrome.google.com/webstore/detail/dbepggeogbaibhgnhhndojpepiihcmeb"&gt;Vimium&lt;/a&gt; extension for &lt;a href="http://www.chromium.org/Home"&gt;Chromium&lt;/a&gt;, and of course Vim for all of my coding. The experiment has been an extremely happy one for me.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/express_screenshot.png" alt="Screenshot of Express windows in Vim" /&gt;&lt;/p&gt;

&lt;h2&gt;Not for everyone&lt;/h2&gt;

&lt;p&gt;I accept that Vim is not for everyone. Casual coders, or anyone who doesn&amp;#8217;t want to get their hands dirty should probably stick with TextMate. Yahuda Katz famously blogged that &lt;a href="http://yehudakatz.com/2010/07/29/everyone-who-tried-to-convince-me-to-use-vim-was-wrong/"&gt;switching to Vim was not easy&lt;/a&gt; and I accept many of his points. Vim isn&amp;#8217;t going to be something you can pick up and use straightaway.&lt;/p&gt;

&lt;p&gt;But if you stick with it you might just see the light. I did and can only give Vim a massive ringing endorsement.&lt;/p&gt;

&lt;h2&gt;Translations of this article&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.fatcow.com/edu/eighteen-months-bg/"&gt;Bulgarian - Albert Ward&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://vimeo.com/user1690209/videos"&gt;Derek Wyatt&amp;#8217;s videos on Vim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://vimcasts.org/"&gt;Vimcasts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://henrik.nyh.se/2011/01/textmate-to-vim-with-training-wheels"&gt;TextMate to Vim with Training Wheels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/macvim/"&gt;MacVim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://yehudakatz.com/2010/07/29/everyone-who-tried-to-convince-me-to-use-vim-was-wrong/"&gt;Everyone Who Tried to Convince Me to use Vim was Wrong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/carlhuda/janus"&gt;Janus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/MXkEd5n-B68" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//vim-eighteen-months-on/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Nifty Unix Tools - sort]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/JWaBjNbry34/" />
    <updated>2011-03-21T00:00:00+00:00</updated>
    <id>http://shapeshed.com//nifty-unix-tools-sort</id>
    <content type="html">&lt;h2&gt;Sort&lt;/h2&gt;

&lt;p&gt;To demonstrate some of the features here is an example CSV file with some of my favorite cheeses:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;1,Brie de Meaux,1.99
&lt;/span&gt;&lt;span class='line'&gt;2,Maroilles,1.13
&lt;/span&gt;&lt;span class='line'&gt;3,Stinking Bishop,1.65
&lt;/span&gt;&lt;span class='line'&gt;4,Munster,1.29
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The file is sorted by the id number in the first column. Let&amp;#8217;s say we want to sort this by the name of the cheese.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sort -k2,2 -t , test.csv
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The -t flag allows us to specify a delimiter which in this case is the comma character. The -k flag lets us specify a key to sort on. The values are the start and end point for the key. This option says take the second value on the line according to the delimiter.&lt;/p&gt;

&lt;p&gt;This gives us an alphabetically sorted list:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;1,Brie de Meaux,1.99
&lt;/span&gt;&lt;span class='line'&gt;2,Maroilles,1.13
&lt;/span&gt;&lt;span class='line'&gt;4,Munster,1.29
&lt;/span&gt;&lt;span class='line'&gt;3,Stinking Bishop,1.65
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Sort also lets us sort numerically so if we wanted to sort on the third price column we can use&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sort -n -k3,3 -t , test.csv
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Here we use the -n flag which say sort numerically and we have shifted the key to the third column.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;1,Brie de Meaux,1.99
&lt;/span&gt;&lt;span class='line'&gt;3,Stinking Bishop,1.65
&lt;/span&gt;&lt;span class='line'&gt;4,Munster,1.29
&lt;/span&gt;&lt;span class='line'&gt;2,Maroilles,1.13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If we want to sort by the cheapest price we can reverse the sort with the -r flag&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sort -r -n -k3,3 -t , test.csv
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This gives us the cheapest price first&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;2,Maroilles,1.13
&lt;/span&gt;&lt;span class='line'&gt;4,Munster,1.29
&lt;/span&gt;&lt;span class='line'&gt;3,Stinking Bishop,1.65
&lt;/span&gt;&lt;span class='line'&gt;1,Brie de Meaux,1.99
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The sort tool can sort strings and numbers in text files and streams. By using keys you can narrow down the search criteria and get the information you want quickly. It also has options clean up dirty data, although for anything non-trivial you&amp;#8217;ll probably want to use something like &lt;a href="http://www.softpanorama.org/Tools/sort.shtml"&gt;sed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is a great little tool for daily use on in the shell and can make output information much easier to read in shell scripts and standard output.&lt;/p&gt;

&lt;h2&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/sort"&gt;sort man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.softpanorama.org/Tools/sort.shtml"&gt;Unix sort command&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/JWaBjNbry34" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//nifty-unix-tools-sort/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Nifty Unix Tools - wc]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/i2f3nKcCLUY/" />
    <updated>2011-03-19T00:00:00+00:00</updated>
    <id>http://shapeshed.com//nifty-unix-tools-wc</id>
    <content type="html">&lt;h2&gt;Word Count&lt;/h2&gt;

&lt;p&gt;Text files have lots of statitics that can be really useful when you want to extract information from them. With the word count tool it is possible to access&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The number of bytes&lt;/li&gt;
&lt;li&gt;The number of lines&lt;/li&gt;
&lt;li&gt;The number of characters&lt;/li&gt;
&lt;li&gt;The number of words&lt;/li&gt;
&lt;/ul&gt;


&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;wc /usr/share/dict/words
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This gives us&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;234936  234936 2486813 /usr/share/dict/words
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The output is [number of lines] [number of words] [number of bytes] [filename].&lt;/p&gt;

&lt;p&gt;We can access each of these statistics individually by passing an option to the command.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# The number of bytes&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;wc -c /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# The number of lines&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;wc -l /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c"&gt;# The number of words&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;wc -w /usr/share/dict/words
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Piping is powerful&lt;/h2&gt;

&lt;p&gt;The wc command really starts to become useful when it is piped to other commands. Here&amp;#8217;s an example we have 5 csv files that are full of data. We want to find out a sum of how many records there are in all five files. We can do this easily by piping the output of the &lt;a href="http://linux.die.net/man/1/cat"&gt;cat&lt;/a&gt; command to wc.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;cat *.csv | wc -l
&lt;/span&gt;&lt;span class='line'&gt;1866
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Done - we have 1866 records across the 5 files.&lt;/p&gt;

&lt;p&gt;Another example might be looking for the number of occurences of a word or pattern in a file. We can combine &lt;a href="http://linux.die.net/man/1/grep"&gt;grep&lt;/a&gt; with wc to achieve this.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;grep &lt;span class="s2"&gt;&amp;quot;union&amp;quot;&lt;/span&gt; /usr/share/dict/words | wc -l
&lt;/span&gt;&lt;span class='line'&gt;41
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;wc is a really useful tool for summing up results and gathering information on text files or streams.&lt;/p&gt;

&lt;h2&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/wc"&gt;wc man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.devdaily.com/unix/edu/examples/wc.shtml"&gt;The Linux wc command (word count)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://showmedo.com/videotutorials/video?name=940050&amp;amp;fromSeriesID=94"&gt;Software Carpentry - Shell Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/cat"&gt;cat man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/cat"&gt;grep man page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/i2f3nKcCLUY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//nifty-unix-tools-wc/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Connecting clients to a Puppet Master]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/zUdCvsdj0q4/" />
    <updated>2011-03-13T00:00:00+00:00</updated>
    <id>http://shapeshed.com//connecting-clients-to-a-puppet-master</id>
    <content type="html">&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;Following on from a &lt;a href="http://shapeshed.com/journal/setting-up-puppet-on-ubuntu-10-04/"&gt;previous post&lt;/a&gt; where I outlined how to set up a Puppet Master server we are now going to look at how to connect a client to the Puppet Master and start to manage the client server. This walkthrough is based on two Ubuntu 10.04.2 LTS servers.&lt;/p&gt;

&lt;h2&gt;Assumptions&lt;/h2&gt;

&lt;p&gt;For the purpose of this walkthrough I&amp;#8217;m going to assume you have a working Puppet Master server as outlined in the &lt;a href="http://shapeshed.com/journal/setting-up-puppet-on-ubuntu-10-04/"&gt;previous post&lt;/a&gt;. I&amp;#8217;m also assuming that you have a client server and that you have either have DNS set up of that you have amended the hosts files of each server so that each can ping the other by hostname. If you are using hosts files your /etc/hosts files should look something like this&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;192.168.3.162 puppetmaster.example.com puppetmaster puppet
&lt;/span&gt;&lt;span class='line'&gt;192.168.3.165 puppetclient.example puppetclient
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;Connect client to server&lt;/h2&gt;

&lt;p&gt;Once we can ping each server make sure the Puppet Master is running&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo puppet master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Then we can connect from the client to the server&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;puppet agent --server puppetmaster --waitforcert 60 --test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You should see&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;info: Creating a new SSL certificate request &lt;span class="k"&gt;for &lt;/span&gt;puppetclient
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now on the server we can see the request that has come in with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;puppet cert --list
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You should see &amp;#8216;puppetclient&amp;#8217;. Now we can sign the certificate with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;puppet cert --sign puppetclient
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The first time I did this I encountered &lt;a href="http://projects.puppetlabs.com/projects/puppet/wiki/Ruby_Ssl_2007_006"&gt;an issue&lt;/a&gt; that complained that the hostname did not match the server certificate. This can be resolved by setting this explicitly in /etc/puppet/puppet.conf&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;[&lt;/span&gt;master&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;certname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;puppetmaster
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now you should have both servers talking to each other and everything configured to start configuring the client with the Puppet Master. After a minute or so you should see the puppet client cache the certificate - this shows that everything is ok.&lt;/p&gt;

&lt;h2&gt;Adding a module&lt;/h2&gt;

&lt;p&gt;Now you can start building modules to be sent to the client server. I started with a module to change the message of the day banner. You can find it &lt;a href="https://github.com/shapeshed/puppet-master/tree/master/modules/motd"&gt;on github&lt;/a&gt;. Once you&amp;#8217;ve added your new module restart puppet.&lt;/p&gt;

&lt;p&gt;Then you can send modules to nodes that you manage. In /etc/puppet/manifests/nodes.pp add this&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;node puppetclient &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  include motd
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;When the client requests an update from the server it will be sent the new configuration and the motd will be updated.&lt;/p&gt;

&lt;p&gt;The Puppet documentation has some &lt;a href="http://docs.puppetlabs.com/learning/manifests.html"&gt;good documentation&lt;/a&gt; on creating manifests.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/zUdCvsdj0q4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//connecting-clients-to-a-puppet-master/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Setting up Puppet on Ubuntu 10.04]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/f9Um_J-Jrh0/" />
    <updated>2011-02-25T00:00:00+00:00</updated>
    <id>http://shapeshed.com//setting-up-puppet-on-ubuntu-10-04</id>
    <content type="html">&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.puppetlabs.com/"&gt;Puppet&lt;/a&gt; is the not quite so new automated server provisioning hotness. It allows you to provision and manage servers automatically from one Puppet Master Server. It is a great solution for quickly bringing up new VPS instances. Here is a quick walkthrough on how to get started on Ubuntu 10.04 LTS&lt;/p&gt;

&lt;h2&gt;Assumptions&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m setting this up on two clean installs of Ubuntu 10.04 LTS Server Edition. If you are using other Linux flavours things should work but your experience may vary.&lt;/p&gt;

&lt;h2&gt;Setup&lt;/h2&gt;

&lt;p&gt;To help learn Puppet I used two &lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt; server instances in &lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;. If you choose to use VirtualBox in the network settings for the virtual machine choose Bridged Adapter to allow a network IP address to be assigned.&lt;/p&gt;

&lt;p&gt;Next I installed the two servers from the .iso and gave the Puppet Master the hostname of puppetmaster and the Puppet Client the name of puppetclient. The rest of the install is standard, selecting no automatic updates, and installing no additional software.&lt;/p&gt;

&lt;h2&gt;Installing Puppet&lt;/h2&gt;

&lt;p&gt;Once you&amp;#8217;ve installed the servers we can get going with the interesting stuff - installing and configuring Puppet. There is a package available for Puppet in aptitude but I found I had issues with this so instead I recommend that you install it via &lt;a href="http://rubygems.org/"&gt;RubyGems&lt;/a&gt; so let&amp;#8217;s get that installed&lt;/p&gt;

&lt;p&gt;First install packages required by Puppet via aptitude&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo apt-get update
&lt;/span&gt;&lt;span class='line'&gt;sudo apt-get install irb libopenssl-ruby libreadline-ruby rdoc ri ruby ruby-dev
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now we can install RubyGems&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/src
&lt;/span&gt;&lt;span class='line'&gt;sudo wget http://production.cf.rubygems.org/rubygems/rubygems-1.5.2.tgz
&lt;/span&gt;&lt;span class='line'&gt;sudo tar -xzf rubygems-1.5.2.tgz
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;rubygems-1.5.2
&lt;/span&gt;&lt;span class='line'&gt;sudo ruby setup.rb
&lt;/span&gt;&lt;span class='line'&gt;sudo update-alternatives --install /usr/bin/gem gem /usr/bin/gem1.8 1
&lt;/span&gt;&lt;span class='line'&gt;sudo gem update --system
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;And finally Puppet&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo gem install puppet
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;All done!&lt;/p&gt;

&lt;h2&gt;Configuring Puppet&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m assuming you have completed the installation of Puppet on both the puppet master and client servers. I&amp;#8217;m working locally so I need to explicity set the ip addresses of my Puppet Master and client in my /etc/hosts file. To find out the internally assigned ip address run&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;ifconfig
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You want the entry that say inet addr: - it should be something like 192.168.3.162&lt;/p&gt;

&lt;p&gt;Then you need to update the /etc/hosts file on each machine with each machine&amp;#8217;s ip address&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;192.168.3.162 puppetmaster.example.com puppetmaster puppet
&lt;/span&gt;&lt;span class='line'&gt;192.168.3.165 puppetclient.example puppetclient
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Now on the Puppet Master you need to set up the puppet configuration in /etc. John Arundel of &lt;a href="http://bitfieldconsulting.com/"&gt;Bitfield Consulting&lt;/a&gt; has created a &lt;a href="http://bitfieldconsulting.com/files/powering-up-with-puppet.tar.gz"&gt;handy tarball&lt;/a&gt; that you can use as a template. Let&amp;#8217;s get it&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc
&lt;/span&gt;&lt;span class='line'&gt;sudo wget http://bitfieldconsulting.com/files/powering-up-with-puppet.tar.gz
&lt;/span&gt;&lt;span class='line'&gt;sudo tar -xzf powering-up-with-puppet.tar.gz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This provides a basic stucture for Puppet configuration. We&amp;#8217;ll come onto writing manifests in a later post. Now we can start the Puppet daemon, making the relevant system users in the process&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo puppet master --mkusers --verbose --no-daemonize
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you see it start then great. I encountered a &lt;a href="http://comments.gmane.org/gmane.comp.sysutils.puppet.bugs/17681"&gt;bug&lt;/a&gt; here that meant the Puppet Master Deamon failed to start. The issue here is that file ownership isn&amp;#8217;t set correctly I fixed this with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;chown -R puppet:puppet /var/lib/puppet
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Once you are sure everything is ok you can daemonize Puppet with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo puppet master
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Finally we can run a local test to make sure that everything is running as expected&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo puppet agent --test --server&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;hostname&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You should see something like&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;info: Caching catalog &lt;span class="k"&gt;for &lt;/span&gt;puppetmaster
&lt;/span&gt;&lt;span class='line'&gt;info: Applying configuration version &lt;span class="s1"&gt;&amp;#39;1298651839&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;notice: Finished catalog run in 0.25 seconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Next we&amp;#8217;ll look at connecting the client to the Puppet Master, creating manifests before moving on to managing users. Stay tuned!&lt;/p&gt;

&lt;h2&gt;Related links&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.puppetlabs.com/"&gt;Puppet Labs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ubuntu.com/"&gt;Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rubygems.org/"&gt;RubyGems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bitfieldconsulting.com/files/powering-up-with-puppet.tar.gz"&gt;Bitfield Consulting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bitfieldconsulting.com/puppet-tutorial"&gt;Puppet Tutorial for Linux: Powering up with Puppet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/f9Um_J-Jrh0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//setting-up-puppet-on-ubuntu-10-04/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Abstracting the design layer]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/foDOdChnTMw/" />
    <updated>2011-02-02T00:00:00+00:00</updated>
    <id>http://shapeshed.com//abstracting-the-design-layer</id>
    <content type="html">&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;Whilst working on a &lt;a href="http://nodejs.org"&gt;node.js&lt;/a&gt; project I realised that using various tools I had extracted the entire design layer of the site.&lt;/p&gt;

&lt;h2&gt;CSS&lt;/h2&gt;

&lt;p&gt;There are now several mature and stable frameworks available to developers to help fill the gaps in CSS. &lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt; is my tool of choice - I&amp;#8217;ve &lt;a href="http://shapeshed.com/journal/sass-is-a-beautiful-thing/"&gt;written about it before&lt;/a&gt;, also I&amp;#8217;ve also been using &lt;a href="http://lesscss.org/"&gt;LESS&lt;/a&gt; on a few projects recently. Using the Sass project you can now also use syntax that is very close to vanilla CSS. Here&amp;#8217;s an example:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='scss'&gt;&lt;span class='line'&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;#3bbfce&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;$margin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nc"&gt;.content-navigation&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="na"&gt;border-color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nf"&gt;darken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nc"&gt;.border&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$margin&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$margin&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="na"&gt;border-color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$blue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I&amp;#8217;m agnostic as to which framework is best but unless the site is very small I always use a frameowrk. Sass can be pre-compiled so it doesn&amp;#8217;t add any overhead when the site is delivered and also provides options on whether the CSS file is pretty printed or compressed for minimum file size. Compass also provides some very useful features for CSS3 support. One common scenario is adding a border radius. As the spec is still in progress browser vendors are using prefixes. &lt;a href="http://compass-style.org/"&gt;Compass&lt;/a&gt; takes account of this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='scss'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@include&lt;/span&gt;&lt;span class="nd"&gt; border-radius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;compiles to&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='css'&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;-webkit-border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;-moz-border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;-o-border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;-ms-border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;-khtml-border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt; &lt;span class="nt"&gt;border-radius&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nt"&gt;4px&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is particularly good as if and when the spec is formalised and a universal syntax is agreed then it is very likely that compass will be updated and you won&amp;#8217;t need to do anything other than regenerate your files.&lt;/p&gt;

&lt;h2&gt;HTML&lt;/h2&gt;

&lt;p&gt;HTML also has a number of templating languages that abstract writing raw HTML. The advantages are mainly syntax checking - the tools won&amp;#8217;t complile if you have an error. If you care about writing valid HTML this ia great idea. For Ruby my tool of choice is &lt;a href="http://haml-lang.com/"&gt;HAML&lt;/a&gt;. In node.js a dialect of HAML is available in &lt;a href="http://jade-lang.com/"&gt;jade&lt;/a&gt;. Here&amp;#8217;s an example of jade.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='jade'&gt;&lt;span class='line'&gt;&lt;span class="nn"&gt;!!! 5&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;html&lt;/span&gt;(&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;)
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;head&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;title&lt;/span&gt; My site
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nt"&gt;h1&lt;/span&gt; Site title
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nf"&gt;#wrapper&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;      &lt;span class="nt"&gt;p&lt;/span&gt; Oh hai!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Particularly when you are interacting with a database and outputting data to views I find these templating languages really useful. Again there are many templating languages available. I&amp;#8217;m agnositc other than my opinion that you should be using one.&lt;/p&gt;

&lt;h2&gt;JavaScript&lt;/h2&gt;

&lt;p&gt;The final piece of the puzzle is JavaScript. JavaScript is a hated and loved language with a great object model at heart. I&amp;#8217;ve been writing native JavaScript for quite a while now so I was interested to find the &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt; project. In the last year JavaScript has become trendy again with node.js and many developers coming from Ruby found JavaScript&amp;#8217;s syntax ugly. CoffeeScript abstracts JavaScript and presents JavaScript in a more Ruby like syntax. In compiling to JavaScript it also runs the code through &lt;a href="http://www.jslint.com/"&gt;JSLint&lt;/a&gt;. I can take or leave the syntax improvements but automatically running the code through a tool that empasises quality is a great sell for me. Here&amp;#8217;s are the examples from the documentation:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='coffeescript'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;song = &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;do&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;re&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;mi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;so&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;singers = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;Jagger: &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Rock&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Elvis: &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Roll&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;bitlist = &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;kids =&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;brother:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Max&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;age: &lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nv"&gt;sister:&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Ida&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nv"&gt;age: &lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Compiles to&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='line'&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;bitlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;singers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;song&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;song&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;do&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;re&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;mi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;fa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;so&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;singers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;Jagger&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Rock&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;Elvis&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Roll&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;bitlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nx"&gt;kids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;brother&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Max&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nx"&gt;sister&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Ida&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Abstracting the entire front-end layer may seem drastic. There is new syntax and frameworks to learn for a start. If you working in a team of more than one developer there may also be a reluctance to move to frameworks. But for me the value is immense. With CSS you can improve code maintainability and defend against the evolving CSS3 spec and implementations. With HTML you can ensure your code is valid and make it more readable with indentation based languages like HAML or jade. With JavaScript you get a prettier syntax (which I can take or leave) but more importantly your code is automatically checked for quality by JSLint. Many JavaScript developers do this anyway but automating this has to be a good thing.&lt;/p&gt;

&lt;p&gt;Frameworks and abstractions are not for everyone and I certainly would not consider using frameowrks on micro or nano projects. But for large complex applications they make a lot of sense to me.&lt;/p&gt;

&lt;h2&gt;Related links&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://sass-lang.com/"&gt;Sass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://lesscss.org/"&gt;LESS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://compass-style.org/"&gt;Compass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://haml-lang.com/"&gt;Haml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jade-lang.com/"&gt;jade&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.jslint.com/"&gt;JSLint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/foDOdChnTMw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//abstracting-the-design-layer/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Getting email through spam filters from a Rails App]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/QVDB4tpddLA/" />
    <updated>2010-12-06T00:00:00+00:00</updated>
    <id>http://shapeshed.com//getting-email-through-spam-filters-from-a-rails-app</id>
    <content type="html">&lt;h2&gt;The Skinny&lt;/h2&gt;

&lt;p&gt;This is a walkthrough on how mail is delivered successfully into the inboxes of Gmail, a Google Hosted Mail account, Hotmail, Yahoo and AOL Mail from a Rails application using &lt;a href="http://www.postfix.org/"&gt;Postfix&lt;/a&gt; on an &lt;a href="http://www.ubuntu.com/server"&gt;Ubuntu 10.04 server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Knowledge of Ruby, DNS and Unix administration is required. If all of that seems to frightening I recommend a service like &lt;a href="http://sendgrid.com/"&gt;Sendgrid&lt;/a&gt; to handle delivery of mail from your Rails app.&lt;/p&gt;

&lt;h2&gt;The Task&lt;/h2&gt;

&lt;p&gt;I followed a test driven approach to this task so set out what I wanted to achieve first. Success criteria for a pass was for mail to be delivered to the inboxes of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gmail&lt;/li&gt;
&lt;li&gt;Google Hosted Mail Account using Postini&lt;/li&gt;
&lt;li&gt;Hotmail&lt;/li&gt;
&lt;li&gt;Yahoo Mail&lt;/li&gt;
&lt;li&gt;AOL Mail&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Initial tests&lt;/h2&gt;

&lt;p&gt;Sending mail from the application without any changes resulted in the following test results&lt;/p&gt;

&lt;p&gt;FAIL: Gmail, Google Hosted Account, Hotmail, Yahoo, AOL&lt;/p&gt;

&lt;h2&gt;Content Level&lt;/h2&gt;

&lt;p&gt;First we looked at the content of the email. It was three lines of text each with a link in. This looked spammy so we decided to flesh out the email a little, taking other web based services as an example. This presented an opportunity for some help text at the end of the email. Useful to the user and useful for the purpose of getting mail through.&lt;/p&gt;

&lt;p&gt;FAIL: Gmail, Google Hosted Account, Hotmail, Yahoo, AOL&lt;/p&gt;

&lt;h2&gt;Application Level&lt;/h2&gt;

&lt;p&gt;I decided to take HTML email out of the equation entirely and deliver plain text mail only. It may be that this gets added back in at a later date but it seemed easier to test things by taking out one variable.&lt;/p&gt;

&lt;p&gt;It is easy to ensure that your Rails app sends email as plain text. Make sure your templates end with .text.plain.erb and the correct mime type will be sent. Note that if you have templates with .text.html.erb these will need to be removed or a multipart email will be sent.&lt;/p&gt;

&lt;p&gt;Following some excellent advice from &lt;a href="http://www.igvita.com/2007/07/21/sendmail-spam-filter-tricks-in-rails/"&gt;Ilya Grigorik&lt;/a&gt; I then ensured that the headers on the emails were correct. In my case the reply to address was different from the from header.&lt;/p&gt;

&lt;p&gt;At this stage messages were getting through Postini but still ending in SPAM in Gmail but were being rejected by Hotmail and Yahoo.&lt;/p&gt;

&lt;p&gt;Partial PASS: Google &amp;amp; Google Hosted Account (delivered but in Spam folder)&lt;/p&gt;

&lt;p&gt;FAIL: Hotmail, Yahoo, AOL&lt;/p&gt;

&lt;h2&gt;Server&lt;/h2&gt;

&lt;p&gt;A &lt;a href="http://www.corvidworks.com/articles/mail-deliverability-tip"&gt;great article by Kenn Wilson&lt;/a&gt; really helped to configure the mail server correctly. To start with there was no fully qualified domain name in place on the server and the reverse DNS was set to the dynamically generated &lt;a href="http://www.slicehost.com/"&gt;Slicehost&lt;/a&gt; address. Firstly a FQDN was set on the server and then a reverse DNS entry was set to point to the FQDN rather than the Slicehost address. This is all detailed in Kenn&amp;#8217;s article so I won&amp;#8217;t duplicate the details here.&lt;/p&gt;

&lt;p&gt;Partial PASS: Google &amp;amp; Google Hosted Account (delivered but in Spam folder)&lt;/p&gt;

&lt;p&gt;FAIL: Hotmail, Yahoo, AOL&lt;/p&gt;

&lt;h2&gt;SPF Records&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.slicehost.com/"&gt;The Sender Policy Framework&lt;/a&gt; allows you to specify a TXT DNS entry that identifies which servers are allowed to send mail for a domain, or subdomain. The Project homepage has a good overview and a wizard to help you set up DNS records.&lt;/p&gt;

&lt;p&gt;Partial PASS: Google &amp;amp; Google Hosted Account (delivered but in Spam folder)&lt;/p&gt;

&lt;p&gt;FAIL: Hotmail, Yahoo, AOL&lt;/p&gt;

&lt;h2&gt;Spamhaus&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.spamhaus.org/lookup.lasso"&gt;Spamhaus&lt;/a&gt; by default blacklists some IPs until they are manually removed. This was the case with our Slicehost IP. There are a few services to see if your domain is blacklisted. &lt;a href="http://www.mxtoolbox.com/blacklists.aspx"&gt;MX Toolbox&lt;/a&gt; offers and excellent free service. If you discover that your IP is listed in Spamhaus there is a process for removing it. Once DNS had propagated we saw messages making it through to Hotmail and Gmail. Still though we were seeing messages ending up in the Spam folder for Yahoo!&lt;/p&gt;

&lt;p&gt;PASS: Google &amp;amp; Google Hosted Account, Hotmail, AOL&lt;/p&gt;

&lt;p&gt;FAIL: Yahoo&lt;/p&gt;

&lt;h2&gt;Domain Keys&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://domainkeys.sourceforge.net/"&gt;Domain Keys&lt;/a&gt; is an idea that Yahoo is behind so I felt there was a  good potential that if Domain Keys were implemented that Yahoo Mail would start to trust the mail. I found a &lt;a href="https://help.ubuntu.com/community/Postfix/DomainKeys"&gt;great walkthrough detailing how to do this&lt;/a&gt; on Ubuntu. I won&amp;#8217;t duplicate that article here, but the short answer is that once DNS had propagated Mail was now being delivered successfully to Yahoo.&lt;/p&gt;

&lt;p&gt;PASS: Google &amp;amp; Google Hosted Account, Hotmail, AOL, Yahoo&lt;/p&gt;

&lt;h2&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;Getting mail delivered from a Rails application to all of these email providers was not an easy task and all in took about a day&amp;#8217;s work. I can now understand why many developers just opt for delivery via a service like SendGrid.&lt;/p&gt;

&lt;p&gt;But having completed the exercise the application now has reliable email delivery to all of these email services without the additional overhead of using a third-party service. I&amp;#8217;m also sure this requirement will come up again so the experience should stand me in good stead.&lt;/p&gt;

&lt;p&gt;If you have anything to add from your own experience please email me and I&amp;#8217;ll update the article.&lt;/p&gt;

&lt;h2&gt;Related links&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://domainkeys.sourceforge.net/"&gt;Domain Keys&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.openspf.org/"&gt;Sender Policy Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.dkim.org/"&gt;Domain Keys Identified Mail&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/QVDB4tpddLA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//getting-email-through-spam-filters-from-a-rails-app/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Nifty Unix Tools - head and tail]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/Z1Y3qSXdlAc/" />
    <updated>2010-11-03T00:00:00+00:00</updated>
    <id>http://shapeshed.com//nifty-unix-tools-head-and-tail</id>
    <content type="html">&lt;h2&gt;Head - view the top of files&lt;/h2&gt;

&lt;p&gt;Head is simple tool to view the top of files. In its simplest form you can use it to see the first ten lines of a file.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;head /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;A
&lt;/span&gt;&lt;span class='line'&gt;a
&lt;/span&gt;&lt;span class='line'&gt;aa
&lt;/span&gt;&lt;span class='line'&gt;aal
&lt;/span&gt;&lt;span class='line'&gt;aalii
&lt;/span&gt;&lt;span class='line'&gt;aam
&lt;/span&gt;&lt;span class='line'&gt;Aani
&lt;/span&gt;&lt;span class='line'&gt;aardvark
&lt;/span&gt;&lt;span class='line'&gt;aardwolf
&lt;/span&gt;&lt;span class='line'&gt;Aaron
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;By default it outputs the first ten lines of a file but you can modify that by passing the -n option&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;head -n 1 /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;A
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In fact you don&amp;#8217;t even need to use -n. You can just use a number.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;head -1 /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;A
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is useful for viewing comments and the the top of files in general but becomes really useful when you pipe things together.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;FILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/some/dir/*.zip
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;SEARCH_STRING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;findme&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;for &lt;/span&gt;f in &lt;span class="nv"&gt;$FILES&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;  &lt;/span&gt;zipinfo -1 &lt;span class="nv"&gt;$f&lt;/span&gt; | grep &lt;span class="nv"&gt;$SEARCH_STRING&lt;/span&gt; | head -1 | awk &lt;span class="s1"&gt;&amp;#39;{ print &amp;quot;Found in: &amp;quot; $1 }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Here we are searching the contents of zip files with a search string but we only want the first occurence. So we can use head to filter the results to just one.&lt;/p&gt;

&lt;h2&gt;Tail&lt;/h2&gt;

&lt;p&gt;Tail is the opposite to head but operates on the end of files.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;zymotoxic
&lt;/span&gt;&lt;span class='line'&gt;zymurgy
&lt;/span&gt;&lt;span class='line'&gt;Zyrenian
&lt;/span&gt;&lt;span class='line'&gt;Zyrian
&lt;/span&gt;&lt;span class='line'&gt;Zyryan
&lt;/span&gt;&lt;span class='line'&gt;zythem
&lt;/span&gt;&lt;span class='line'&gt;Zythia
&lt;/span&gt;&lt;span class='line'&gt;zythum
&lt;/span&gt;&lt;span class='line'&gt;Zyzomys
&lt;/span&gt;&lt;span class='line'&gt;Zyzzogeton
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It also accepts the -n argument for the number of lines you want&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail -n 1 /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;Zyzzogeton
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This also works passing just a number&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail -1 /usr/share/dict/words
&lt;/span&gt;&lt;span class='line'&gt;Zyzzogeton
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Watching log files&lt;/h2&gt;

&lt;p&gt;Tail has the option to watch files in real time so you can keep an eye on log files. You can enable this by passing the -f option.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tail -f /Users/george/Sites/myrailspp/log/development.log
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is really useful for watching logs. You can use it for watching apache, mail logs - any file!&lt;/p&gt;

&lt;p&gt;head and tail are simple tools but are extemely useful for everyday usage, especially in piping so worth understanding!&lt;/p&gt;

&lt;h2&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/head"&gt;head man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://linux.die.net/man/1/tail"&gt;tail man page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.devdaily.com/blog/post/linux-unix/linux-head-tail-commands"&gt;The Linux head and tail commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/Z1Y3qSXdlAc" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//nifty-unix-tools-head-and-tail/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Installing Passenger 3 with RVM and Nginx on OSX]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/OpKNOnZF-jM/" />
    <updated>2010-10-21T00:00:00+01:00</updated>
    <id>http://shapeshed.com//installing-passenger-3-with-rvm-and-nginx-on-osx</id>
    <content type="html">&lt;h2&gt;Nginx&lt;/h2&gt;

&lt;p&gt;My preferred way of installing nginx on OSX is using &lt;a href="http://github.com/mxcl/homebrew"&gt;homebrew&lt;/a&gt;. You need to compile it with passenger support&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install nginx --with-passenger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;RVM&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://rvm.beginrescueend.com/rvm/install/"&gt;RVM&lt;/a&gt; makes it easy to manage multiple rubies. Installation is easy&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;bash &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt; curl http://rvm.beginrescueend.com/releases/rvm-install-head &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;You can then install different versions of ruby. In this case let&amp;#8217;s install &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise Edition&lt;/a&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rvm install ree
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then we can make Ruby Enterprise Edition the default Ruby on this machine with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;rvm --default ree
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Passenger&lt;/h2&gt;

&lt;p&gt;This is the most tricky part of the install. To start you&amp;#8217;ll need the passenger gem&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;gem install passenger
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;We need to use the nginx source code for this process. If your homebrew setup is a default one run&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tar -xzf /Users/george/Library/Caches/Homebrew/nginx-0.8.53.tar.gz
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Note your version of nginx may be different from this!&lt;/p&gt;

&lt;p&gt;Then we need to run the nginx passenger module installer&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;passenger-install-nginx-module
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The default install downloads an entirely new binary for Nginx - a bit annoying. If you choose option 2 you&amp;#8217;ll be able to choose the source you&amp;#8217;ve downloaded with homebrew. For the source directory choose the one we&amp;#8217;ve just extracted&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/Users/george/Library/Caches/Homebrew/nginx-0.8.53
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then choose to install Nginx to (if you&amp;#8217;ve used the default homebrew install)&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;/usr/local/Cellar/nginx/0.8.53/sbin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Hit return on the next two prompts. Drink tea whilst it compiles.&lt;/p&gt;

&lt;p&gt;The installer spits out some configuration for you. Open up /usr/local/etc/nginx/nginx.conf in your favourite text editor and paste this in.&lt;/p&gt;

&lt;p&gt;Then you just need to create a virtual host&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;foo.local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="s"&gt;/webapps/foo.com/public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;passenger_enabled&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Provided you&amp;#8217;ve added foo.local to your /etc/hosts file you should be able to start the server and see your site using&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sudo nginx
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Running multiple virtual hosts&lt;/h2&gt;

&lt;p&gt;Passenger 3 adds a killer feature - the ability to run a standalone passenger and proxy using Nginx and TCP sockets. The process for this is to first setup a virtual host to proxy through to a socket&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='nginx'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;bar_upstream&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="s"&gt;unix:/tmp/bar.local.socket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;bar.local&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="s"&gt;/webapps/bar.local/public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://bar_upstream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then start a standalone instance of Passenger. This downloads and complies a new binary of Nginx for some reason&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;passenger start --socket /tmp/bar.local.socket -d --nginx-version 0.8.53
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This is explained in more detail on the &lt;a href="http://blog.phusion.nl/2010/09/21/phusion-passenger-running-multiple-ruby-versions/"&gt;Phusion Blog&lt;/a&gt;. Because the standalone passenger is invoked within an RVM context it is completely possible to have different ruby versions and gemsets. TOTAL WIN!&lt;/p&gt;

&lt;p&gt;It should then be trivial use something like &lt;a href="http://mmonit.com/monit/"&gt;Monit&lt;/a&gt; to make sure that the process for virtual hosts is running and start / stop it.&lt;/p&gt;

&lt;p&gt;This setup can be applied to a Linux server too to create a flexible Rails stack with multiple hosts, Rubies and gemsets.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/OpKNOnZF-jM" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//installing-passenger-3-with-rvm-and-nginx-on-osx/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Background job nirvana with Resque, Redis and God]]></title>
    <link href="http://feedproxy.google.com/~r/shapeshed/~3/Mcm5rAguUPA/" />
    <updated>2010-09-08T00:00:00+01:00</updated>
    <id>http://shapeshed.com//background-job-nirvana-with-redis-resque-and-god</id>
    <content type="html">&lt;h2&gt;Resque&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://github.com/defunkt/resque/"&gt;Resque&lt;/a&gt; is a Ruby library that lets you place jobs on queues and process them later. It was created by &lt;a href="http://chriswanstrath.com/"&gt;defunkt&lt;/a&gt; and is in production use on &lt;a href="http://github.com"&gt;Github&lt;/a&gt;. The documentation is excellent. I&amp;#8217;m using Resque on a Rails app but it can be used with any Rack application.&lt;/p&gt;

&lt;p&gt;First you need to install &lt;a href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt;. On OSX this is trivial with &lt;a href="http://github.com/mxcl/homebrew"&gt;homebrew&lt;/a&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install redis
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;If you installed Redis with homebrew it spits out some helpful information about how to start Redis on boot or you can start the server with&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;redis-server
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The installation notes for Resque are excellent so I won&amp;#8217;t repeat them here - head over to the &lt;a href="http://github.com/defunkt/resque/blob/master/README.markdown"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Booting the GUI&lt;/h2&gt;

&lt;p&gt;Resque ships with an great GUI that lets you track jobs and workers. To launch it from the root of your site run&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;resque-web
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Then you&amp;#8217;ll probably want to spawn some workers&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;QUEUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;* rake resque:workers
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In the GUI you should now see 5 workers waiting to do your bidding&lt;/p&gt;

&lt;p&gt;&lt;img src="http://shapeshed.com/images/articles/resque_workers.png" alt="Workers in the Resque GUI" /&gt;&lt;/p&gt;

&lt;p&gt;Now you can start sending jobs to Resque and watch your workers eat them up. The GUI also provides a great way to review failures. The stack trace is even included!&lt;/p&gt;

&lt;h2&gt;Settings for production&lt;/h2&gt;

&lt;p&gt;There are a few issues to consider in production. Firstly if your Redis server is used by other applications you might want to specify a namespace for the application to use. You can do this by adding the following to an initialiser after Redis is configured.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="no"&gt;Resque&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;resque:YourApp&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;As Redis supports running multiple databases on a server it may be possible to specify which database to use but that wasn&amp;#8217;t a requirement for me. I couldn&amp;#8217;t find anything in the documentation about this. If anyone knows anything about this let me know and I&amp;#8217;ll update the post.&lt;/p&gt;

&lt;p&gt;In production it will be important that Redis and the workers have high availability. Redis can easily be configured to start on reboot but &lt;a href="http://god.rubyforge.org/"&gt;God&lt;/a&gt; can also monitor a live system and restart Redis if necessary. God is another Ruby based library for monitoring services on a server. The configuration files are written with Ruby so it is easy to extend it to whatever you&amp;#8217;d like. Using God we can easily make sure our workers are well-managed and that if Redis does go down it will be restarted. There is even an &lt;a href="http://github.com/defunkt/resque/blob/master/examples/god/resque.god"&gt;example script&lt;/a&gt; in Resque that will get you started with managing workers.&lt;/p&gt;

&lt;p&gt;With God running on the server we can be sure that Redis and our workers will have high availability, or that we&amp;#8217;ll know about it quickly if not.&lt;/p&gt;

&lt;h2&gt;General win&lt;/h2&gt;

&lt;p&gt;Adding a highly available and robust background queue to the application took less than a day. Thanks to &lt;a href="http://chriswanstrath.com/"&gt;defunkt&lt;/a&gt; and &lt;a href="http://tom.preston-werner.com/"&gt;mojombo&lt;/a&gt; for their excellent open source libraries!&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/shapeshed/~4/Mcm5rAguUPA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://shapeshed.com//background-job-nirvana-with-redis-resque-and-god/</feedburner:origLink></entry>
  
</feed>

