Pull request Compare This branch is 2 commits ahead, 2 commits behind isaacs:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Installing a Node service on a Joyent SmartMachine

This article will teach you how to get up and running with Node.js on a SmartOS SmartMachine from Joyent. Since SmartOS uses Solaris under the hood, we'll be leveraging some of its awesome package powers.

To make things a bit simpler, we're just going to create a server that does nothing but the normal Hello World! web server. You can of course us the same techniques for any more advanced node program.

This article's content and the code samples are also available on Github. If you prefer to follow along at home with the git repo handy, be my guest:

git clone http://github.com/isaacs/joyent-node-on-smart-example.git

It'll save a bit of wgetting and curling.

Step 1: Get Your SmartMachine

Head on over to Joyent and provision yourself up a shiny new SmartMachine. I got mine at To make this a bit easier, I set up a variable in my bash session so that I wouldn't have to keep typing that.

export smart=

When your SmartMachine gets created, you'll get an email with a bunch of passwords. You'll probably want to change those.

I personally like to send my pubkeys so I don't have to enter the password every time, but that's up to you:

scp ~/.ssh/*.pub admin@$smart:~/.ssh/

Everything that we'll be doing from here on out will be on the SmartMachine, so sign in:

ssh admin@$smart

Change the root password to something crazy:

sudo passwd root

Change the admin password while you're in there:


Installing node and npm

Make sure that ~/local/bin is in your $PATH. That's where we'll have npm install things, so that we don't have to use sudo.

echo 'export PATH=$HOME/local/bin:${PATH}' >> ~/.bashrc

Install node:

sudo pkgin update
sudo pkgin install nodejs

Because Solaris has a slightly different tar program, and npm expects the GNU-compatible version, we'll set that as a config option ahead of time:

echo tar = gtar >> ~/.npmrc

Because we've installed node in a global location, we also need to tell npm where to put modules and executables. Otherwise you have to use sudo with npm, which is very not recommended.

echo root = $HOME"/.node_libraries" >> ~/.npmrc
echo binroot = $HOME"/local/bin" >> ~/.npmrc
echo manroot = $HOME"/local/share/man" >> ~/.npmrc

At this point, npm will work by default, without requiring any special privileges. Go ahead and bootstrap it:

curl http://npmjs.org/install.sh | sh

Now you should be able to run npm, use the node repl, etc. While we aren't going to be using npm in this demo, it's super handy to have it there if you want to install any of the popular node libraries.


We're going to be installing a node web server on port 80, so if your SmartMachine has Apache or Nginx pre-installed, we'll have to disable those so that they don't get in the way.

If that's the case, run these commands to turn off those other servers:

sudo svcadm disable apache
sudo svcadm disable nginx

The Hello, world! program

For demonstration purposes, we'll just write a little hello world program.

First, create a folder where our program is going to live:

mkdir hello-world

You can grab the file itself from the github repo, or probably just crank it out from memory if you've been messing around with node long enough:

require("http").createServer(function (req, res) {
  res.writeHead(200, {})
  res.end("Hello, world!")
console.log("waiting to say hello.")

(Feel free to get a little more creative with it.)

Save that to ~/hello-world/server.js.

Pause for Reflection

Let's make sure everything is kosher at this point.

$ which node

$ sudo node hello-world/server.js
waiting to say hello.

Then hit your SmartMachine URL and make sure it says Hello, world!

If anything is broken, now's the time to fix it, because we're about to dive into Solaris service land.

Define the Service

"Services" in Solaris are first-class citizens in the OS. Each service has an XML manifest file that defines it. The svccfg command is used to add one of these config files to the system, and svcadm is used to administrate services once they're defined.

I went ahead and created a node-hello-world-service-manifest.xml file for this purpose. So, download that, and add it to the system configuration:

wget http://github.com/isaacs/joyent-node-on-smart-example/raw/master/node-hello-world-service-manifest.xml
sudo svccfg import node-hello-world-service-manifest.xml

If you've cloned the git repo, then you can of course svccfg it from there, instead.

It's outside the scope of this article to go through all the different settings and what they do. Most are pretty self-explanatory (folder paths and such). For more info than you ever wanted to know about smf template files, see man 5 smf_template.

Start the Service

Starting a service is a simple one-liner:

sudo svcadm enable node-hello-world-service

To stop the service is also predictably simple:

sudo svcadm disable node-hello-world-service

Once you get tired of stopping and starting the service, start it one last time, and then load up your SmartMachine URL in a web browser. If it says Hello, world!, then congratulations, you're done! You can quit while you're ahead, or read on to learn a few tricks you can use when it breaks.


The services in Solaris each have a log file based on the name that they're defined with. For ours, the log file lives at /var/svc/log/site-node-hello-world-service:default.log. If something doesn't work right, you can view the last few log messages like this:

tail -n 50 "/var/svc/log/site-node-hello-world-service:default.log"

Solaris will give it a reasonable try to restart your service if it crashes, which is a really nice feature. But, if it keeps crashing, it'll give up, and put the service into "maintenance" mode.

For instance, if the server can't be started, you might see a bunch of log messages that look like this:

[ Sep 14 00:55:56 Stopping because all processes in service exited. ]
[ Sep 14 00:55:56 Executing start method ("/home/admin/local/bin/node /home/admin/hello-world/server.js"). ]
[ Sep 14 00:55:56 Stopping because all processes in service exited. ]
[ Sep 14 00:55:56 Executing start method ("/home/admin/local/bin/node /home/admin/hello-world/server.js"). ]
[ Sep 14 00:55:56 Stopping because all processes in service exited. ]
[ Sep 14 00:55:56 Executing start method ("/home/admin/local/bin/node /home/admin/hello-world/server.js"). ]
[ Sep 14 00:55:56 Stopping because all processes in service exited. ]
[ Sep 14 00:55:56 Restarting too quickly, changing state to maintenance. ]

If this happens, first of all, make sure that the site will start up if you do it manually. This will uncover most problems.

sudo /home/admin/local/bin/node /home/admin/hello-world/server.js

The sudo is required because we're listening on port 80.

You can also get information about a service by using the svcs command. For example, if our site thrashes itself into maintenance mode, you might see this:

$ svcs -lp node-hello-world-service
fmri         svc:/site/node-hello-world-service:default
name         node.js hello-world service
enabled      true
state        maintenance
next_state   none
state_time   September 13, 2010  5:55:56 PM PDT
logfile      /var/svc/log/site-node-hello-world-service:default.log
restarter    svc:/system/svc/restarter:default
dependency   require_all/refresh svc:/milestone/network:default (online)
dependency   require_all/refresh svc:/system/filesystem/local (online)

Once you've fixed whatever was preventing the site from starting properly, you can restart it by doing the following:

svcadm disable node-hello-world-service
svcadm enable node-hello-world-service

Note that once you go into maintenance mode, your service must be disabled before it can be re-enabled.

At this point, the logs should look like this:

$ tail -5 /var/svc/log/site-node-hello-world-service\:default.log 
[ Sep 14 00:55:56 Restarting too quickly, changing state to maintenance. ]
[ Sep 14 01:09:04 Leaving maintenance because disable requested. ]
[ Sep 14 01:09:04 Disabled. ]
[ Sep 14 01:09:07 Enabled. ]
[ Sep 14 01:09:07 Executing start method ("/home/admin/local/bin/node /home/admin/hello-world/server.js"). ]

And hitting the site in a web browser or curl should show it working.