- We should stop having software handle system tasks like daemonization or privilege-dropping
- That’s a job for a supervisor. For example we use Upstart
- Nodejs plays nicely with Upstart, article links to an Upstart script for launching a nodejs application
We are currently building a webapp with the following stack: nodejs, mongoDB, nginx and redis. We also use a certain number of services, like Jenkins and Graphite. To use these softwares in production, we need to be able to daemonize them, run them as specific users (usually with low privileges), and have tham restart automatically if case of an unexpected crash.
These are quite common needs. But people are often confused as to what part of the system is responsible for what task. I often see software handling the privilege drop (for example the otherwise excellent Graphite), or the daemonization (for example gunicorn - which is also great otherwise). It’s bad, because as a result, some of these softwares don’t play nicely with supervisors like Upstart. People tend to resort to strange and not well understood scripts (I even saw an Upstart script that called the start_stop_daemon to launch a gunicorn process which daemonized itself!).
There is a simple rule to follow to avoid this confusion: softwares should not daemonize or handle privilege drop. These are jobs for the supervisor. That’s all, separation of concerns, folks. For example, we use Upstart to launch our processes as services. That way, we get added benefits: they get respawned in case they crash, they restart automatically if we need to reboot the server, and we can specify rules such as “service A should not start before service B has started and is ready”. I see no reason not to it that way!
An example of software that respects these rules is nodejs. Here is the Upstart script we use with it. It enables us to start our app as any user, log all output and get the added benefits I was referring to earlier. It really is all you need with nodejs and most software you will use. This is not an Upstart tutorial (their doc is pretty good), but let me explain the most important parts:
- The privilege drop is done through the
su -s /bin/sh -c 'exec "$0" "$@"' $RUN_AS -- commandpart. This line executes
$RUN_AS. Unfortunately, we have to use this method because the standard
sudo -udoesn’t work from within an Upstart script.
- The log file needs to be
touched in case it doesn’t exist, then
chowned to user
$RUN_AS, because otherwise it will belong to user root (which the user executing the Upstart script)
- The rest is pretty standard
Of course, this script doesn’t work just for nodejs! So you have no excuse not to use it now :)