DIY node.js server on Amazon EC2

I’m involved with a project where our ruby/rails developer dropped out, so I decided to take on the job using node.js (rather than learn rails). We initially were using services from dotCloud, but it was too flakey from day to day and our demo was coming up. For hosting, Amazon’s EC2 was the obvious candidate, but I’d have to setup and provision the entire server from scratch. This is that story πŸ™‚

Here’s what we’ll do

  • choose a Linux image
  • create a HelloWorld node.js server
  • use git to push code changes to the server
  • automatically restart node after pushing with git
  • set up node to run long term using supervisor

Setup a New EC2 Instance

launch a new Ubuntu instance

First things first, login to your AWS console and launch a new Ubuntu Linux image for your new EC2 server. Select the Community AMIs tab and search for this one:

099720109477/ebs/ubuntu-images/ubuntu-maverick-10.10-i386-server-20101225

I choose Ubuntu over other Linux distributions because more of what I needed was already available via the standard package manager (redis, couchdb, etc…). At this point, I usually assign an elastic IP address to my new instances before proceeding with ssh.

update your new system

Once your new instance is up and running, login and update the system. The upgrade might take some time.

$ sudo apt-get update
$ sudo apt-get -y upgrade

install the rcconf service utility

This will make it easy to manage services

$ sudo apt-get install rcconf

install some build tools including git

$ sudo apt-get install build-essential
$ sudo apt-get install libssl-dev
$ sudo apt-get install git-core

libssl-dev is needed to use the crypt node.js package

build node

You can view the [node.js installation instructions](https://github.com/joyent/node/wiki/Installation “Node.js installation”) or just follow what I did.

$ wget http://nodejs.org/dist/node-latest.tar.gz
$ tar xzf node-latest.tar.gz
$ cd node-v0.4.7
$ ./configure --prefix=/usr
$ make
$ sudo make install

I used –prefix=/usr to install node on the existing PATH. make install can take quite a while… go brew some espresso.

install the node package manager npm:

Get the latest npm from github and install.

$ cd ~
$ git clone http://github.com/isaacs/npm.git
$ cd npm
$ sudo make install

get some really good node packages πŸ™‚

$ cd ~
$ npm install connect redis connect-redis jade express express-resource futures emailjs

install a web server

$ sudo apt-get install nginx

Edit the nginx default configuration file replacing the root (/) location section

$ sudo vi /etc/nginx/sites-enabled/default

Use a proxy passengry entry. This will forward your requests to your node server

location / {
    proxy_pass          http://127.0.0.1:8124/;
}

Restart ngnix

$ sudo /etc/init.d/nginx restart

Hello New Server!

create a directory for your node server

$ mkdir ~/www
$ cd ~/www

create a HelloWorld server

$ cat > server.js

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

Start the server

$ node server.js

test your new server

Test in a browser by navigating to http://your.static.ip/

Shutdown your new server before continuing…

Bring in Source Control!

Now we’ll get to the good part where we can leverage git to deploy new server code

create a remote repository for our node project

Create a bare repository outside the www folder

$ mkdir ~/repo
$ cd ~/repo
$ git init --bare

create a git hook

Create a post-recieve hook that will copy over new code after it’s been pushed to the repository

$ cat > hooks/post-receive

#!/bin/sh
GIT_WORK_TREE=/home/ubuntu/www
export GIT_WORK_TREE
git checkout -f

$ chmod +x hooks/post-receive

add this remote repository to your LOCAL repository:

On your local development machine, setup a repository for your new server

$ mkdir helloworld
$ cd helloworld
$ git init
$ git remote add ec2 ssh://ubuntu@your.static.ip/home/ubuntu/repo

create a local HelloWorld node server

$ cat > server.js

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');

add and commit it to your local repository

$ git add server.js
$ git commit -m 'first'

push our local code changes to the remote repository:

$ git push ec2 +master:refs/heads/master

you only need to specify +master:refs/heads/mast the first time

test your new server

Test in a browser by navigating to http://your.static.ip/

Have Your Node Server Run Forever

dotCloud uses supervisor to keep node servers up after reboot and crashing. We’ll do the same. So, back on your EC2 instance:

$ sudo apt-get install python-setuptools
$ sudo easy_install supervisor

install it as a service

$ curl https://raw.github.com/gist/176149/88d0d68c4af22a7474ad1d011659ea2d27e35b8d/supervisord.sh > supervisord
$ chmod +x supervisord
$ sudo mv supervisord /etc/init.d/supervisord

set the service to start on boot

check the supervisord service in the services list using rcconf

$ sudo rcconf

create a configuration file

$ sudo echo_supervisord_conf > supervisord.conf
$ sudo mv supervisord.conf /etc/supervisord.conf

edit the new configuration file

$ sudo vi /etc/supervisord.conf

change the permissions of the [unix_http_server]

chmod=0777                 ; sockef file mode (default 0700)

set the user that supervisord runs as to be ‘ubuntu’

This is under the [supervisord] section

user=ubuntu

add a section that describes your node server

Note that we can set the NODE_ENV variable here.

[program:node]
command=node server.js
directory=/home/ubuntu/www
environment=NODE_ENV=production

reload supervisord

$ supervisorctl reload

You can also restart the service

$ /etc/init.d/supervisord restart

restart supervisord when changes are pushed

In the post-recieve git hook we previously created, append a final command that restarts supervisord

$ vi ~/repo/hooks/post-receive

#!/bin/sh
GIT_WORK_TREE=/home/ubuntu/www
export GIT_WORK_TREE
git checkout -f
sudo supervisorctl restart node

That’s It πŸ™‚

Now you can work on a local development machine, push your changes to the server using git, sit back and relax while the post-recieve hook tells supervisor to restart your node server. Refresh the browser and throw the confetti!

Activating a WordPress Child Theme in Code

I ran into this problem while building a mobile version of a WordPress theme. To support a mobile version, I decided to make a child theme that had bare-bones CSS and other mobile goodies. I wanted this child theme to be active when requests came in from known mobile and handheld devices.

Using the filters ‘template‘ and ‘stylesheet‘ in my parent theme’s functions.php , I was able to override the default theme and use my child theme instead.

I hit a snag though, when using get_template_part(). It was ALWAYS deferring to my parent theme for files!
Continue reading

Patterns for Using Theme Styles and Scripts

I’m bundling more functionality into my WordPress themes instead of into plugins these days. The best way I’ve found to handle extra scripts and styles is to use the functionsΒ wp_register_script, wp_enqueue_script, wp_register_style and wp_enqueue_style. These functions are used to setup the scripts and styles we’ll be using for our site. By sticking to these functions, WordPress will include these in the HTML when wp_head() is called, usually inside our header.php file.
Continue reading

How to setup git’s difftool on Windows

In this little recipe, we’re going to teach git on Windows how to run our own custom diff tool when we execute git difftool. The diff tool I’m using is WinMerge.

We’ll need to enter a few new configuration options on the command line:

git config --global diff.tool winmerge
git config --global difftool.winmerge.cmd "C:/git-difftool.bat \"$LOCAL\" \"$REMOTE\""
git config --global difftool.prompt false

Then create your wrapper script at C:/git-difftool.bat. Git will call this script when executing git difftool. That script should look like:

"C:/Program Files (x86)/WinMerge/WinMergeU.exe" -e -ub "$1" "$2"

Yes, this is using bash syntax in Windows shell! It works thanks to git, so you can execute git difftool from either the git shell or from Windows shell.

NOTE: backslashes won’t work in regular widows shell, but WILL in git shell — I know, weird! πŸ™‚

There you are! Now you can enjoy git on Windows (ok, just kidding) AND on Linux!

Using git to Remotely Install Website Updates

There’s a great recipe for this at Using Git to manage a web site. I thought I’d share my version of it, just slightly modified from the original and HostGator-centric. Even if you’re using shared hosting, you may still be able to use git to remotely install updates to your sites.

I was pleasantly surprised to discover that HostGator DOES include git in it’s shared hosting packages. You’ll need ssh access for this recipe to work — an extra hoop for HostGator customers using shared hosting.

Continue reading