Recently I gave myself simple task to test out tiny node.js app on server. While starting it manually is no brainer but it made me think more when I wanted to make it work as background service.
Usually I do it in
/etc/init.d/ folder by creating bash script and run it from there, it is reliable, it is how httpd starts. But after some googling I found people talking about upstart and monit, I did feel like caveman, but took it seriously and opened upstart cookbook and just started to evaluate how should I eat it and if it is poisonous.
So after some digging I did decide to run node.js with upstart just because its new to me and its philosophy of event driven approach seems close to node. But challenges just began.
Upstart is not supported in all distros, and I was lucky that centos supports it and has version pre-installed, but sadly its
0.6.5 which is away from now latest
1.5. I could have downloaded latest package and “try” to install it but I thought it is not worth the effort to just try out small node app.
My upstart version is 0.6.5, so how should I take care of starting node as background service. Well first thing is to specify user for node to run. I did install node from binary tarball to
/usr/share/node/node-v0.8.9-linux-x64, later created
apps folder in
/usr/share/node and added sample express3 app from node
passport-local module examples. Then created user
node and changed
/usr/share/node ownership recursively to
node user with
chown -R node /usr/share/node.
By default app will not even start as it has some dependencies but those could be handled with npm which comes with node installation by default.
Next step was to start this app as a background service as title of this article says. For a service aka job to be started by upstart it is required to put
*.conf file into
/etc/init/ directory. In upstart
1.4 and upwards it could be placed into
$home/.init/ but not in my case. Upstart is evented system so basically you react to events on system and do your stuff, you can also emit your own events and catch those in other scripts. So in my case I had to write simple script which listens to some sort of startup event and starts app after it gets one, so after reading docs and googling I came up with louischatriot’s script found on github:
# /etc/init/node.conf description 'node system startup' author 'ivarprudnikov.com' env NAME=AppName env LOG_FILE=/usr/share/node/some.log env USER=node env NODE_BIN=/usr/share/node/node-v0.8.9-linux-x64/bin/node env SCRIPT_FILE=/usr/share/node/apps/examples/express3/app.js start on runlevel  stop on runlevel  # Respawn in case of a crash, with default parameters respawn script # Make sure logfile exists and can be written by the user we drop privileges to touch $LOG_FILE chown $USER:$USER $LOG_FILE # recommended approach in case of su/sudo usage so that service does not fork exec su -s /bin/sh -c 'exec "$0" "$@"' $USER -- $NODE_BIN $SCRIPT_FILE >> $LOG_FILE 2>&1 end script post-start script echo "app $NAME post-start event" >> $LOG_FILE end script
After saving file it is possible just to run it with
initctl start node and app should be started.
But after restart I did not see it running, so what was wrong?? I found answer on serverfault and debug file to test out events fired in the system:
# /etc/init/debug.conf start on ( starting JOB!=debug \ or started JOB!=debug \ or stopping JOB!=debug \ or stopped JOB!=debug ) script exec 1>>/tmp/log.file echo -n "$UPSTART_JOB/$UPSTART_INSTANCE ($0):$$:`date`:" echo "Job $JOB/$INSTANCE $UPSTART_EVENTS. Environment was:" env echo end scripts
So now after looking into
/tmp/log.file I could choose which event to listen to and start node app. I changed:
start on runlevel  stop on runlevel 
start on started network stop on stopping network
So now app is running in background, restarts in case of failure, starts on startup. Things to consider are hooking to events which are important to node, it would be possible to have
nginx set up in this way and then:
start on ( started network and started nginx )