How to use Ubuntu's Upstart to Control Node.js Forever

Mar 6 2013

Recently I needed to start a server written in Node.js. This server was deployed on Ubuntu 12.04, and I wanted it to be started using the system's init system. Yet I also wanted the safety of Forever, a script manager for Node.js.

Ubuntu still supports the classic SysV init style, but it also now supports the far more sophisticated Upstart system. It is appealing for a few reasons: One is that it feels simpler and cleaner. Another is that it is more powerful and easily more configurable. I decided to use it for my scripts.

This article explains how to use Upstart, Forever, and Node.js together to run a Node.js server as a daemon process that is automatically started at system startup, and automatically stops at shutdown or reboot. <!--break-->

An Upstart File

The first thing to do is create an Upstart configuration file. I keep mine in my source code along with the app, and copy it into /etc/init when I install onto the server.

# node-example.conf

description     "Example of starting Node with Upstart and Forever"

# Start up when the system hits any normal runlevel, and 
# shuts down when the system goes to shutdown or reboot.
start on filesystem or runlevel [2345]
stop on runlevel [06]

# IMPORTANT: You will want to use this with Forever. It
# tells Upstart that forever is going to fork after it
# starts.
expect fork

# This monitors Forever, which seems gratuitous.
# TIP: Comment these out while debugging your script.
respawn limit 5 30

# Send error messages to the console. Useful for debugging.
console output

# exampleuser is a very low-privileged user. We run as
# this user instead of as root (the default user).
setuid exampleuser

# The user's home directory
env HOME=/home/exampleuser

# Now we run Forever, telling it to write its logs to
# /tmp, and to run the script /opt/example/server.js
        cd $HOME
        exec forever start -a -l /tmp/forever.log -o /tmp/forever.stdout.log -e /tmp/forever.stderr.log /opt/example/server.js
end script

Upstart has quite a few configuration options. The above is minimal, but if you have more sophisticated needs, you might want to check out the (well written) manual for Upstart.

Starting and Stopping

Once you have a configuration file like the one above, you can drop it in /etc/init and then test it using the initctl script.

My configuration file is node-example.conf, so to start it, I issue this command:

$ sudo start node-example

Just because it looks like it started okay doesn't necessarily mean that it did. You can use ps -ef to see if your node processes are running. Even more telling, though, is the output of this command:

$ sudo initctl list

Output should look something like this:

mountall-net stop/waiting
passwd stop/waiting
rc stop/waiting
rsyslog start/running, process 708
screen-cleanup stop/waiting
tty4 start/running, process 738
udev start/running, process 299
upstart-udev-bridge start/running, process 293
ureadahead-other stop/waiting

That will list all of the start/stop scripts and tell you the status of each. node-example should be in that list, and should be listed as start/running with a PID. If it is listed as stop/waiting, then either the Forever process died or your expect setting (in the config file) is not correct.

As I debugged my script, I found the most difficult part had to do with permissions for my setuid user. It's important that the user be able to write to the $HOME directory, since that is where Forever stores its .forever directory.